feat(finance): oracle legacy integration, bulk params import (multipart), master data expansion, and formula UI polish#54
Merged
ilramdhan merged 21 commits intoJun 27, 2026
Conversation
…s + parameter display_order ERP Items page (/finance/erp-items): full CRUD table with create/edit/delete dialogs, active/inactive filter, search, and pagination. Hooks and BFF routes wired to the new CreateCostErpItem, UpdateCostErpItem, DeleteCostErpItem RPCs. Route graph editor: AddStageDialog now accepts optional metadata (route_name, route_item_code, route_shade_code, route_shade_name) in a collapsible section. AddRmDialog accepts optional rm_shade_code, rm_shade_name, notes, sub_type. Route head notes textarea added below the status/version line (edit-mode only). Parameter dialog: display_order numeric input added per-row so operators can set the display order when adding applicable parameters to a product. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… to product master form Removed /finance/erp-items page, its BFF routes, and components — ERP items are Oracle sync replicas and have no management UI. Added a collapsible "Legacy / Import identifiers" section to the product master create/edit dialog with three plain text inputs: Oracle Sys ID (flex02), ERP Compound Key (flex01), and Type Label (flex03). These are free-text fields for operators who migrate data from legacy Oracle systems — no validation beyond max length. Form resets correctly, values round-trip through BFF → gRPC → DB. Updated CostProductMaster type, normalizer, and payload interfaces to include flex01/02/03 throughout the frontend data layer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ompound Key / Type Label columns ERP linkage (erp_item_code, erp_grade_code_1/2) was a separate workflow to bind products to Oracle ERP items via a combobox picker. Now that legacy identifiers are plain text inputs (flex01/02/03), the linkage modal and its infrastructure are no longer needed. Removed: ErpLinkageDialog component, /erp-linkage BFF PUT route, useUpdateErpLinkage hook, UpdateErpLinkagePayload type, erpItemCode/erpGradeCode/erpLinked* fields from CostProductMaster interface and normalizer, "ERP linkage" table column, Link2 action button from table. Added: "Oracle Sys ID" (flex02), "ERP Compound Key" (flex01), "Type Label" (flex03) columns to the product master table and detail page — same data, no extra UI layer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tend entirely ERP item as an RM source type (ITEM) is removed from the routing editor — only PRODUCT (upstream stage) and GROUP (RM group / cons-stock-PO) are valid RM sources. Deleted: ErpItemCombobox, all three cost-erp BFF routes (items/grades/shades), use-cost-erp hooks, cost-erp types, getCostErpClient from grpc client registry. Routing AddRmDialog: removed ITEM SelectItem option and itemPick state; default source type changed to PRODUCT; GROUP description updated to "RM group (cons/stock/PO)". RmRefType still includes "ITEM" for backward compat with existing DB data — legacy routes that have ITEM-type RMs will still display correctly, just can't add new ones. Backend CostErpLookupService (ListCostErpItems/Grades/Shades) is left in place for the future Oracle sync ETL — no backend changes needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Machine: +mpPerDay, ohsPerDay, sparesPerDay, kgsLostChange, vb1Qty–vb5Qty. MBSpin: +mbsCc, mbsCostRateMkt. ProductGrade: +pgDetailProduct, pgGradeLabel, stdSellingPrice, spValue. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Extends machine master CRUD with 9 optional cost/volume fields sourced from the Oracle 142 migration: mpPerDay, ohsPerDay, sparesPerDay, kgsLostChange (cost fields) and vb1Qty–vb5Qty (volume bucket thresholds). Also adds mpPerDay and kgsLostChange display columns to machine table. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Add mbsCc field to form schema (string, max 100) - Add mbsCostRateMkt field to form schema (number, min 0, optional, nullable) - Add default values for both fields in form initialization - Add edit population logic to extract values from existing spin data - Add payload construction for create and update mutations - Add form fields: CC Code input and MB Rate MKT number input with 6 decimal places - Add mbsCostRateMkt column to table with USD formatting ($X.XXXX or em dash) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add 4 new fields to ProductGrade form and table: - pgDetailProduct: Detail Product Pattern (Oracle CMPG_DETAIL_PRODUCT match key) - pgGradeLabel: Grade Label (STD_VALUE_LOSS parameter value) - stdSellingPrice: Std Selling Price (BC_SPECIAL_PROD value) - spValue: SP Value (VALUE_LOSS value) Changes: - Updated Zod schema with new fields (pgDetailProduct/pgGradeLabel optional, numeric fields with min(0)) - Added new section "Grade Lookup Fields" in form with 2-column grid - Added pgDetailProduct column to product grade table after bcRecoveryRate - Updated create/update payloads with new fields Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…rade lookup fields Both pgDetailProduct and pgGradeLabel are optional fields that should be omitted from the payload when empty (to let backend treat as null), not sent as empty strings. Fixed in both create and update mutation payloads with type assertions to bridge the proto-generated type expectations. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
New BFF routes: POST /api/v1/finance/costing/import/bulk_params_only → ImportBulkParamsOnly gRPC GET /api/v1/finance/costing/template/bulk_params_only → ExcelJS 2-sheet template ParamsOnlyImportDialog: upload + queue UI for product_parameters / applicable_params files. No pre-validate step (backend handles all-or-nothing atomically). Shows a warning about unknown param codes; links to import-jobs after queuing. Product master page: "Import Params Saja (Bulk)" added to the Import dropdown menu. Service: bulkImportParamsOnly + downloadParamsOnlyTemplate exported from cost-import-api.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p zone, template card, done state Replaced minimal button-based layout with the standard import dialog pattern: - Template download as a bordered card (FileSpreadsheet icon + description + Download button) - Drag-and-drop dashed border file picker with file name + size display - AlertCircle warning about all-or-nothing validation and missing_param_codes report - Done state with CheckCircle + job ID + "View Import Jobs" link (same as BulkImportDialog) - step machine: upload → submitting → done Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d import handler
The frontend template was severely out of sync with what the backend actually reads,
which would have caused imports to silently fail or populate wrong columns.
Changes per sheet:
- product_master: rename flex_01 → legacy_erp_compound_key, flex_03 → legacy_type_label
- product_parameters: add missing data_type column (required by backend validator)
- route_head: add missing routing_status column
- route_sequences:
- rename legacy_oracle_sys_id → route_head_legacy_product_id
- add node_product_legacy_id (separate FK for the DAG node product)
- replace position_x, position_y, cyl_type_id (UI-only, not read by import) with
route_shade_code, route_shade_name
- route_rms:
- rename legacy_oracle_sys_id → route_head_legacy_product_id
- move ratio to correct position (col 5, after rm_type)
- remove rm_item_code_ref (not read by backend)
- add rm_shade_code, rm_shade_name
All headers are documented inline with their purpose and FK relationships.
Header row now has bold + light grey fill for readability.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ling UI Root cause of 429: bulkImportParamsOnly was encoding a 50 MB binary file as a JSON number array (~200 MB text) → exceeded Next.js body parser and gRPC limits. Fixes: - BFF route: accept multipart/form-data (binary bytes, no JSON inflation); falls back to legacy JSON body for backward compat with small files - Service: bulkImportParamsOnly() now sends FormData instead of JSON - gRPC client CHANNEL_OPTIONS: max_receive/send 10 MB → 100 MB (matches server) Dialog rewrite (ParamsOnlyImportDialog): - Matches ImportDialog style: template card, dashed file picker, warning panel - Background job: submits → polls job status every 3 s → shows progress bar - Terminal states: Done (green with row count) / Failed (red with link to Jobs) - Step machine: upload → submitting → polling → done/failed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…d forms Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…bles+forms Machine: add 6 Oracle fields to form (mcPoyBobbinWeight, mcTotFxdCst, mcBobbinPerTrolly, mcBoxCost, mcCaptivePerBobbin, mcWeightage) in new "Oracle Machine Data" section; add Weightage + Bobbin Wt columns to table. BoxBobbinCost: add bbnReuseVal + boxReuseVal fields to form Rates & Reuse section; wire into create/update mutations. MBSpin: add mbsStatus + mbsFinalProduct columns to table; add mbsStatus, mbsLdrPrsn, mbsFinalProduct fields to form. MBHead: add mbhStatus + mbhCheckStatus columns to table; add mbhCheckStatus, mbhStatus, mbhLdrPrsn, mbhFinalProduct, mbhCode fields to form in new "Oracle Data" section. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…rm and table - Regenerate types/generated/finance/v1/formula.ts with 8 new enum values (CONDITIONAL, LOOKUP, RM_LOOKUP, FROM_MARKETING, INTERMINGLING, SNAPSHOT, PENDING, INITIAL_VALUE) - Expand FORMULA_TYPE_LABELS, FORMULA_TYPE_OPTIONS, and FORMULA_TYPE_FORM_OPTIONS in types/finance/formula.ts - Add all new types to validTypeValues in formula-form-dialog.tsx - Show input params picker only when type is CALCULATION; hide it for all other types (FROM_MARKETING has 0 inputs by design; others vary) - result_param field remains shown for all non-UNSPECIFIED types Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…params INPUT-category params (e.g. AX_WT) can be formula outputs — Oracle design allows FROM_MARKETING and CALCULATION formulas to write into INPUT params. The previous dropdown only showed CALCULATED params, causing FROM_MARKETING formula result params to appear blank in the form. Changes: - resultParamPool = CALCULATED + INPUT (sorted by code) - Dropdown label shows param category (calculated/input) for clarity - Description updated to reflect both categories are valid outputs Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Prevent user from selecting the same param as both input and output. Backend already blocks this with ErrCircularReference — this adds early client-side feedback before the API call. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…drawer
List page:
- Wrap table in Card with CardHeader + CardDescription (matches product-requests pattern)
- Add loading={isLoading} to all KpiCards (cardinal rule compliance)
- Replace raw <input> period filter with shadcn Input
- Replace raw UUID display with <UserName> in "By" column
- Replace <Badge> status with <StatusBadge type="cost">
Detail page:
- Add PageHeader with back-to-list button and product code/name title
- Bento grid layout: lg:col-span-8 main + lg:col-span-4 audit sidebar
- Fix header card gap: always show productCode/#id on left so CardHeader is never empty
- Fall back to useCostProductMaster when GetCostResult returns empty productCode/productName (backend gap)
- Replace UUID "calculatedBy" with <UserName> in card and history table
- Replace <Badge> status with <StatusBadge> throughout
- Fix loading state to proper skeleton
Breakdown modal → Sheet drawer:
- Convert Dialog to Sheet (side="right", sm:max-w-3xl) matching FillParamDrawer pattern
- Clean header: product name as SheetTitle, code+period+calcType+version as SheetDescription, no badge clutter
- shadcn TabsList grid w-full grid-cols-4 — full-width pill tabs, not boxy
- Parameter snapshot grouped by displayGroup from useProductRequiredParams (proper grouping vs prefix heuristic); falls back to "General" group
- Formula cards redesigned: compact div.rounded-lg.border, code+name header row, ArrowRight icon for output param
- Tables wrapped in overflow-x-auto rounded-md border
- Fall back to useCostProductMaster for product name in drawer header
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Pull Request ini menghadirkan perubahan besar terkait cara sistem kita berintegrasi dengan data legacy Oracle. Sistem ERP Linkage lama telah dihapus sepenuhnya dan digantikan dengan integrasi plain-text (flex01/02/03) di level Product Master. Selain itu, PR ini memperkenalkan fitur Bulk Import khusus untuk Parameter (menggunakan
multipart/form-datauntuk mengatasi limitasi payload 429), mengekspos puluhan kolom data Oracle baru pada modul Yarn Master, serta menyempurnakan alur kerja pembuatan Formula dengan tipe-tipe baru dan validasi circular reference.Type of Change
Module/Component Affected
Changes Made
1. Oracle Legacy & Product Master Refactor:
ERP Itemsdan modalERP Linkagekarena entitas ini merupakan replika sync Oracle dan tidak memerlukan UI manajemen mandiri. OpsiITEMjuga dihapus dari sumber RM (hanya menyisakanPRODUCTdanGROUP).flex02), "ERP Compound Key" (flex01), dan "Type Label" (flex03) ke form Product Master.display_order(numerik) pada dialog parameter dan metadata spesifik (route_shade_code,route_name, dll) di dalam editor grafik rute (route graph).2. Params-Only Bulk Import & System Scaling:
product_parameters/applicable_params) lengkap dengan progress bar, sistem polling job background, dan UI interaktif (sama seperti BulkImportDialog utama).multipart/form-data(biner murni tanpa di-inflate ke JSON) dan menaikkan limit gRPC channel ke 100MB. Hal ini menyelesaikan masalah crash saat mengunggah file biner berukuran besar (~50MB).flex_01/flex_03, menambahkandata_type,routing_status, dll).3. Master Data Expansion (Yarn Master):
Machine,MBSpin,ProductGrade,MBHead, danBoxBobbinCost.undefined(bukan empty string) apabila kosong, agar backend dapat memprosesnya sebagai nilai null.4. Formula Management System:
CONDITIONAL,LOOKUP,FROM_MARKETING, dll) dan hanya memunculkan input params picker jika tipenyaCALCULATION.CALCULATED, tapi jugaINPUT, untuk mengakomodasi desain Oracle di mana tipe marketing/calculation bisa mengisi input parameter.Related Issues
Fixes #
Related to #
Screenshots
Before
After
Testing Performed
Manual Testing
Browser Testing
Build Verification
npm run lintpassesnpx tsc --noEmitpassesnpm run buildsucceedsAccessibility
Performance
Pre-merge Checklist
Reviewer Notes
bulk_params_only. File sekarang dikirim sebagai binary payload multipart murni alih-alih dikonversi ke JSON Array. Ini merupakan perbaikan vital demi skalabilitas pembacaan berkas raksasa tanpa memory leak atau status 429 Too Many Requests/Payload Too Large.