Skip to content

feat(ppc): add RM identity labels, plan-item, and work-order carry-forward contracts - #53

Merged
ilramdhan merged 3 commits into
mutugading:mainfrom
ilramdhan:fix/production-plan-and-chat-bot-ai
Aug 4, 2026
Merged

feat(ppc): add RM identity labels, plan-item, and work-order carry-forward contracts#53
ilramdhan merged 3 commits into
mutugading:mainfrom
ilramdhan:fix/production-plan-and-chat-bot-ai

Conversation

@ilramdhan

Copy link
Copy Markdown
Member

Description

This PR introduces PPC domain contract enhancements for RM identity resolution and carry-forward functionality:

  • RM Identity Labels: Adds rm_code and rm_name to CostMasterRouteRm and WORmAllocation, along with route attribution fields (route_stage_name, route_level, route_rm_ratio) to allow displaying readable RM details and stage provenance without requiring external database joins.
  • Plan-Item Carry-Forward: Adds contracts for carrying uncovered plan items into target months, introducing PlanCarryAction, PlanCarryCandidate, and provenance fields (carry_from_item_id, carry_action) on PlanItem.
  • Work-Order Carry-Forward: Adds WO-level carry-forward contracts, introducing WorkOrderCarryCandidate with ineligibility_reason, updating lot_no validation constraint to max_len 30, and allowing carry_qty to accept empty strings for full remainder defaults.

Change Type

  • ✨ New service/message
  • ➕ Add field/RPC/enum value
  • 🔄 Modify validation
  • 📝 Documentation update
  • ⚠️ Deprecation
  • 🔧 Config/script changes

Proto Files Changed

  • common/v1/common.proto
  • finance/v1/uom.proto
  • Other: ppc/v1/*.proto

Changes Made

  • RM Identity Resolution & Route Attribution:
    • Added rm_code and rm_name fields to CostMasterRouteRm (derived server-side by rm_type: PRODUCT, ITEM, GROUP).
    • Added rm_code, rm_name, route_stage_name, route_level, and route_rm_ratio fields to WORmAllocation.
  • Plan-Item Carry-Forward Contracts:
    • Added PlanCarryAction enum (tailored for plan items without DEFERRED or SPLIT states).
    • Added carry_from_item_id and carry_action fields to PlanItem for provenance and duplicate detection.
    • Added PlanCarryCandidate message providing coverage details (qty_covered, qty_uncovered, work_order_count).
  • Work-Order Carry-Forward Contracts:
    • Added WO-level carry-forward contracts producing CONTINUATION WOs in target months.
    • Added WorkOrderCarryCandidate containing ineligibility_reason to explicitly signal ineligible WOs.
    • Updated lot_no field validation to max_len 30 to match database column limits (VARCHAR(30)).
    • Updated carry_qty validation pattern to permit empty strings, enabling default full remainder carry functionality.

Related Issues

Fixes #
Related to #

Breaking Change Check

Is this a breaking change?

  • No - buf breaking passes
  • Yes - Requires version bump

Breaking Change Evidence

# Output of buf breaking command
buf breaking --against '.git#branch=main'

Lint Check

# Output of buf lint
buf lint

Generated Code Preview (Optional)


Pre-merge Checklist

  • I have read and followed RULES.md
  • buf format -w applied
  • buf lint passes
  • buf breaking passes
  • Comments document new messages/fields
  • REST mappings follow conventions
  • Validation rules are complete
  • Field numbers are logical

Impact Assessment

  • Backend code regeneration required
  • Frontend code regeneration required
  • OpenAPI spec regeneration required

Reviewer Notes

  • RM identity resolution fields in CostMasterRouteRm and WORmAllocation are read-time decorations resolved at the API boundary; no database schema modifications are required.
  • Aligning lot_no length validation to 30 characters matches database column limits (VARCHAR(30)), preventing potential runtime driver errors during inserts.

ilramdhan and others added 3 commits August 4, 2026 08:53
…racts

A work order's RM allocation stores only crm_rm_id, and a route edge only its
type-discriminated master key. Neither is renderable, so every consumer that
wanted to show an RM had to either display a raw id or make a join it has no
access to — PPC lives in a separate database from the finance masters.

Resolve the labels at the boundary that can actually do it:

- CostMasterRouteRm gains rm_code/rm_name, derived server-side by rm_type
  (PRODUCT -> cost_product_master, ITEM -> cost_erp_item, GROUP ->
  cst_rm_group_head). Empty when the referenced master row is missing, so a
  dangling edge still surfaces rather than vanishing.
- WORmAllocation gains rm_code/rm_name plus route attribution
  (route_stage_name, route_level, route_rm_ratio) so an allocation line can
  explain which stage proposed it and at what per-unit coefficient.

Both are read-time decorations; nothing new is persisted.

Authored-By: Ilham R <ilhamram332@gmail.com>
Co-Authored-By: Ilham R <me@ilramdhan.dev>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: IT Mutugading <it@mutugading.com>
Co-Authored-By: Indra Putro <indraputro@mutugading.com>
Co-Authored-By: Ilham R <ilham.ramadhan@mutugading.com>
Co-Authored-By: IT Mutu Gading <mutugadingapps@gmail.com>
Uncovered plan items at month end had no way forward: the planner could carry a
demand, but the plan items derived from it were left behind and had to be
re-planned by hand. This adds the plan-item level equivalent.

PlanCarryAction is deliberately narrower than CarryAction. A plan item has no
DEFERRED state to move into, and SPLIT would need per-child machine groups and
timelines that a demand split never carries — offering either would mean
accepting a request the domain cannot honour.

PlanItem gains carry_from_item_id and carry_action so a carried item states its
own provenance, which is also what makes an already-carried source detectable
per target month instead of globally.

PlanCarryCandidate reports coverage (qty_covered / qty_uncovered /
work_order_count) alongside the item and its demand label, so the planner
decides from what is actually left rather than from the original target.

Authored-By: Ilham R <ilhamram332@gmail.com>
Co-Authored-By: Ilham R <me@ilramdhan.dev>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: IT Mutugading <it@mutugading.com>
Co-Authored-By: Indra Putro <indraputro@mutugading.com>
Co-Authored-By: Ilham R <ilham.ramadhan@mutugading.com>
Co-Authored-By: IT Mutu Gading <mutugadingapps@gmail.com>
A work order that ran out of month with qty left had no continuation path. This
adds the WO-level carry, producing a CONTINUATION WO in the target month.

WorkOrderCarryCandidate carries ineligibility_reason rather than filtering
ineligible WOs out. A silently absent row reads as "nothing left to carry",
which is the one thing the planner must not conclude when the real answer is
"this WO is closed" or "it was already carried".

Two validation bounds are worth naming:

- lot_no is max_len 30, matching work_order.wo_lot_no VARCHAR(30) as every
  other lot_no field in the file does. At 50 a 31..50-char lot cleared
  validation and then failed at INSERT as a raw driver error, reaching the
  planner as a 500 instead of a field-level complaint. Generated lots are 10
  chars, so nothing real is excluded.
- carry_qty admits the empty string, because unset means "carry the full
  remainder" — the documented default. A pattern that required at least one
  digit would have made the documented default unrepresentable.

Authored-By: Ilham R <ilhamram332@gmail.com>
Co-Authored-By: Ilham R <me@ilramdhan.dev>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: IT Mutugading <it@mutugading.com>
Co-Authored-By: Indra Putro <indraputro@mutugading.com>
Co-Authored-By: Ilham R <ilham.ramadhan@mutugading.com>
Co-Authored-By: IT Mutu Gading <mutugadingapps@gmail.com>
@ilramdhan ilramdhan added this to the Costing Release Milestone milestone Aug 4, 2026
@ilramdhan ilramdhan self-assigned this Aug 4, 2026
Copilot AI lite review requested due to automatic review settings August 4, 2026 03:37
@ilramdhan ilramdhan added bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request feat fix labels Aug 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ilramdhan
ilramdhan merged commit f1f05c5 into mutugading:main Aug 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request feat fix

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants