From f8d060efec00eef304f89015a6b3f83918d839f2 Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 07:53:41 +0900 Subject: [PATCH 01/10] =?UTF-8?q?MBOM=E3=81=AE=E8=A1=8C=E3=81=AB=E6=B6=88?= =?UTF-8?q?=E8=B2=BB=E5=B7=A5=E7=A8=8B=E3=82=92=E6=8C=81=E3=81=9F=E3=81=9B?= =?UTF-8?q?=E3=80=81=E3=83=90=E3=83=83=E3=82=AF=E3=83=95=E3=83=A9=E3=83=83?= =?UTF-8?q?=E3=82=B7=E3=83=A5=E3=82=92=E3=81=9D=E3=81=AE=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E3=81=AE=E4=BD=9C=E6=A5=AD=E6=8C=87=E7=A4=BA=E3=81=A7=E3=81=A0?= =?UTF-8?q?=E3=81=91=E5=BC=95=E3=81=8F=E3=82=88=E3=81=86=E3=81=AB=E3=81=99?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit バックフラッシュが作業指示の工程にかかわらず指図の予定材料をすべて引いていたため、 複数工程の品目で工程ごとにバックフラッシュすると部材が工程数ぶん減っていた。 - BomItem / ManufacturingOrderMaterial に RoutingSequence(消費工程=工順の工程順序)を追加。 工順は一括置換で行が作り直されるため、IDではなく工程順序で指す - 未指定の行は最終工程で消費する。展開時に予定材料へ最終工程の工程順序を入れて固定する - 工順に無い工程順序を指すMBOMの品目は指図の展開で拒否する(MBOMと工順の登録順は自由なため展開時に照合) - 消費する部材の無い工程でのバックフラッシュは拒否する - MBOM画面・指図詳細に消費工程を表示、MBOMのCSVに RoutingSequence 列を追加 - サンプル 15_bom.csv は実績サンプルの部材投入に合わせて工程10にした - Spec.md 改訂117、利用者ガイド(マスタ・実行・トラブル対応)を更新 MES.md: B-40-10-09(バックフラッシュ)、A-40-10-01/04(MBOM登録・付加情報) Co-Authored-By: Claude Opus 5.5 --- Spec.md | 6 +- docs/execution.md | 2 + docs/masters.md | 6 + docs/troubleshooting.md | 2 + samples/master-csv/15_bom.csv | 18 +- .../ManufacturingOrdersController.cs | 2 +- .../Controllers/ProductsController.cs | 2 +- src/MesApp.Api/Localization/ApiText.en.resx | 12 + .../Services/ManufacturingOrderService.cs | 22 +- src/MesApp.Api/Services/MasterCsvKinds.cs | 1 + .../Services/MasterCsvService.Import.cs | 2 + src/MesApp.Api/Services/MasterCsvService.cs | 1 + .../Services/ProductStructureService.cs | 1 + .../Services/WorkOrderExecutionService.cs | 13 +- .../Pages/ManufacturingOrderDetail.razor | 3 +- .../Masters/Products/ProductBomEditor.razor | 31 +- src/MesApp.Client.Web/Shared/UiText.en.resx | 12 + .../Contracts/Masters/MasterContracts.cs | 6 +- .../Production/ProductionContracts.cs | 3 +- src/MesApp.Core/Entities/Masters.cs | 7 + src/MesApp.Core/Entities/Production.cs | 7 + ...4608_AddBomItemRoutingSequence.Designer.cs | 4753 ++++++++++++++++ ...0260922224608_AddBomItemRoutingSequence.cs | 38 + .../MesAppDbContextModelSnapshot.cs | 6 + ...4610_AddBomItemRoutingSequence.Designer.cs | 4950 +++++++++++++++++ ...0260922224610_AddBomItemRoutingSequence.cs | 38 + .../MesAppDbContextModelSnapshot.cs | 6 + ...4613_AddBomItemRoutingSequence.Designer.cs | 4929 ++++++++++++++++ ...0260922224613_AddBomItemRoutingSequence.cs | 38 + .../MesAppDbContextModelSnapshot.cs | 6 + tests/MesApp.Api.Tests/ExecutionTests.cs | 52 + tests/MesApp.Api.Tests/MasterCsvTests.cs | 9 +- tests/MesApp.Api.Tests/ProductionTests.cs | 20 + 33 files changed, 14974 insertions(+), 30 deletions(-) create mode 100644 src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.Designer.cs create mode 100644 src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.cs create mode 100644 src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.Designer.cs create mode 100644 src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.cs create mode 100644 src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.Designer.cs create mode 100644 src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.cs diff --git a/Spec.md b/Spec.md index 7e576fb..3d02b74 100644 --- a/Spec.md +++ b/Spec.md @@ -115,6 +115,7 @@ 改訂114: 2026-09-23(3.8節・5.2節:同じ製造日・品目・工程で、作業区の範囲が重なる生産計画(作業区なしと作業区あり、上位の段と配下の段)を併存させないようにした。予実は作業区違いの計画を合算するため、全体の計画と内訳の計画が並ぶと二重に数えていた。兄弟の作業区どうしは併存できる。判定は `ProductionPlanPolicy` に置き、単票API(409)とCSV取込(既存との間・ファイル内とも行エラー)の両方から呼ぶ。既に重なって登録されている計画はそのまま残る) 改訂115: 2026-09-23(3.8節・7.2節:生産計画をマスタの一括ZIPの取込・出力から外した(改訂113で含めていた)。生産計画はマスタではなく日々増える業務データで、全期間がZIPに入り、マスタを別環境へ移すと過去の計画まで付いていったため。取込の仕組み(キーで上書き)は引き続きマスタCSVのものを使う。計画のCSV出力は全件をやめ、一覧と同じ絞り込みの `api/production-plans/csv` を追加した。あわせて、3か月分の実績サンプルと同じ期間の生産計画のサンプル `samples/production-plans/` を追加し(`scripts/New-SampleBulkActuals.ps1` が乱数を使わず生成。実績の内容は変えない)、リリースに `samples-production-plans.csv` として添付する。利用者向けガイド(生産管理・ロールと権限など)に生産計画・予実の操作を追記) 改訂116: 2026-09-23(3.8節:実績CSVに出荷指示 `shipping-orders`・出荷判定 `shipment-judgments`・出荷実行 `shipments` を追加した。サンプルの実績で出荷だけが画面操作で、製造から出荷までをCSVだけではたどれなかった。判定と出荷で取込の権限が違うため3種別に分ける。出荷判定の登録・承認を `ShipmentJudgmentsController` から `ShipmentJudgmentService` へ移し、単票APIとCSV取込の両方から呼ぶ。出荷指示は後続のCSVから指すため出荷番号の手入力を許す(`SH〜` は自動採番用として拒否)。サンプル `samples/actual-csv/13〜15` を追加) +改訂117: 2026-09-23(3.9節・5.1節・5.2節:MBOMの行に消費工程(`BomItem.RoutingSequence`。親品目の工順の工程順序)を追加した。バックフラッシュが作業指示の工程にかかわらず指図の予定材料をすべて引いていたため、複数工程の品目で工程ごとにバックフラッシュすると部材が工程数ぶん減っていた。バックフラッシュはその作業指示の工程で消費する部材だけを引き、消費する部材の無い工程では拒否する。未指定の行は最終工程で消費し、展開時に予定材料へ最終工程の工程順序を入れて固定する。工順は一括置換で行が作り直されるためIDではなく工程順序で指し、工順に無い工程順序は展開時に拒否する。MBOMのCSVに `RoutingSequence` 列を追加し、サンプル `samples/master-csv/15_bom.csv` は実績サンプルの部材投入に合わせて工程10とした) 参考: みんなのMES(min-MES) https://min-mes.com/ / OSS: https://github.com/mihatama/open-mes-project --- @@ -351,6 +352,7 @@ AGV/AMR連携(D-50-20-02)・リサイクル管理(D-50-30-02)・VMI/外 - 代替材料は**MBOMの代替部品グループへ登録することで表現する**。同一グループ内で主材料でない行には代替部品フラグを立て、**その行の部材を投入するときは代替理由の入力を必須**とする(誰がどの理由で代替を認めたかを実績に残すため。A-40-10-04)。主材料の投入は理由不要 - 代替理由は投入実績(`MaterialConsumption`)へ代替フラグとともに保存し、監査ログにも記録する。代替そのものへの承認フロー(別の承認者による事前承認)は初期リリースでは行わない[将来拡張] - バックフラッシュ(B-40-10-09)はMBOMから投入部材を導くため、この照合は元から満たしている。ただし**代替部品の行はバックフラッシュで消費しない**(主材料の代わりに使う部材なので、主材料と両方を原単位ぶん引くと二重に減る。また代替の投入には理由が要るが、バックフラッシュは理由を受け取らない)。代替部品を使った場合は手動の部材投入で理由とともに記録する + - **バックフラッシュは、その作業指示の工程で消費する部材だけを引く**。MBOMの行に消費工程(親品目の工順の工程順序)を持たせ、未指定の行は最終工程で消費する。消費工程は展開時に予定材料へ固定し、未指定の行はその時点の最終工程に解決して入れる。工順に無い工程順序を指すMBOMの品目は指図を展開できない(MBOMと工順は別々に改訂でき、どちらを先に登録してもよいため、登録時ではなく展開時に照合する)。消費する部材の無い工程でバックフラッシュを指定したときは拒否する(黙って何も引かないと、引いたつもりの在庫がずれる) - **採番**:指図番号・ロット番号等(`MOyyyyMMdd-0001`、`品目コード-yyyyMMdd-001`)は、**採番テーブル(`NumberSequence`)のプレフィックス1行を更新してから読む**ことで払い出す。既存番号の最大値+1では、同時に採番したリクエストが同じ番号を得て一意制約違反になるため - 採番列が無い場合(採番テーブル導入前のデータ)は、既存番号の最大値の次から始める - **採番列ができたあとに、同じ形式の番号を手入力で登録すると衝突しうる**(採番側はその番号を知らない)。衝突は409で返るため、操作をやり直せば次の番号で成立する。供給者のロット番号など、自動採番と別形式の手入力は影響を受けない @@ -397,7 +399,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと | SkillMaster(スキル・資格マスタ) | コード、名称、種別(スキル/資格)、有効期限管理要否(F-20-10-01) | | UserSkill(従業員スキル・資格) | ユーザーID、スキル/資格ID、取得日、有効期限、状態(F-20-10-02〜05) | | Product(品目マスタ) | 品目コード、品目名、単位、規格、品目区分(製品/半製品・中間品/部材)、標準不良率、**既定ロケーション**(推奨ロケーション指示の第一候補。D-10-30-03) | -| BomItem(MBOM明細) | 親品目ID、子品目ID(部材)、必要数量(親1単位あたり)、内外製区分、代替部品グループ、**代替部品フラグ**(同一グループ内の主材料でない行。A-40-10) | +| BomItem(MBOM明細) | 親品目ID、子品目ID(部材)、必要数量(親1単位あたり)、内外製区分、代替部品グループ、**代替部品フラグ**(同一グループ内の主材料でない行。A-40-10)、**消費工程**(工順の工程順序。未指定なら最終工程。B-40-10-09) | | Process(工程マスタ) | 工程コード、工程名、工程区分(内製/外注) | | Routing(工順/BOP) | 品目ID、工程順序、工程ID、標準作業時間(**1個あたり**)、標準段取り時間(**1回あたり**)、必要スキルID、**候補設備**・治工具、**作業区**、工程管理項目、チェックリストID、**作業手順書ID**(A-40-20、I-30-20)
標準時間の予実(3.2節 B-60-10-05)は 段取り時間+作業時間×数量 で予定を出す | | RoutingEquipment(工順の候補設備) | 工順ID、設備ID(同一工順で一意)。同じ工程を複数の装置で実行できる場合に列挙し、差立ではこの中から1台を選ぶ(B-10-20-02) | @@ -421,7 +423,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと |---|---| | ProductionPlan(生産計画) | 製造日、品目ID、工程ID、作業区ID(任意)、計画数量(0以上)、備考。一意キーは製造日・品目・工程・作業区(作業区なしの重複はAPIで止める)。同じ製造日・品目・工程で作業区の範囲が重なる計画(作業区なしと作業区あり、上位の段と配下の段)は併存させない(予実で二重に数えるため。兄弟の作業区は可)。既存の指図・実績からは参照しない(A-30-10-01) | | ManufacturingOrder(製造指図) | 指図番号、品目ID、数量、納期、指図区分(通常/リワーク/突発)、状態(未承認/承認済/展開済/完了/取消)、承認者、元指図ID(リワーク時)(A-20、B-70-10) | -| ManufacturingOrderMaterial(指図の予定材料) | 指図ID、部材品目ID、原単位(親1単位あたり)、予定数量(=原単位×指図数量)、代替部品グループ。展開時にMBOMから固定し、部材投入の照合とバックフラッシュの基準にする(A-40-10、B-30-20) | +| ManufacturingOrderMaterial(指図の予定材料) | 指図ID、部材品目ID、原単位(親1単位あたり)、予定数量(=原単位×指図数量)、代替部品グループ、消費工程(未指定のMBOM行は展開時の最終工程に解決。本項目の追加前に展開した指図は空で、最終工程として扱う)。展開時にMBOMから固定し、部材投入の照合とバックフラッシュの基準にする(A-40-10、B-30-20) | | WorkOrderControlItem(作業指示の工程管理項目) | 作業指示ID、工程管理項目ID、**展開時点のスナップショット**(項目コード・名称・単位・版数・指示値・許容下限/上限)。実績の逸脱判定と画面表示はこれを使い、マスタの現在値を参照しない(B-30-30-04) | | WorkOrderStatusHistory(作業指示の状態履歴) | 作業指示ID、変更前状態、変更後状態、契機(差立/着手/実績入力/承認/指図取消)、備考、変更者、変更日時。配布・着手・完了・承認・取消の遷移を業務履歴として残す(B-10、B-30-30、B-40-10-10) | | WorkOrder(作業指示) | 指示番号、製造指図ID、品目ID、工程ID、計画数、着手順、割当作業者ID、割当設備ID、**作業区(展開時の工順スナップショット)**、**作業手順書IDと展開時点の版数**、状態(未配布/配布済/着手/完了/承認済)(B-10) | diff --git a/docs/execution.md b/docs/execution.md index 95ba93c..6330e19 100644 --- a/docs/execution.md +++ b/docs/execution.md @@ -131,6 +131,8 @@ next_title: 物流・在庫管理 チェックを入れると、**MBOM × (良品数 + 不良数)** で必要量を計算し、 在庫から **先入れ先出し** で自動的に引き落とします。 +引き落とすのは、MBOMで**この工程を消費工程にした部材だけ**です(消費工程を指定していない部材は最終工程で引きます)。 +各工程でチェックを入れても、部材が二重に減ることはありません。

対象品目のMBOMが未登録だとエラーになります(MBOMが未登録のためバックフラッシュできません。)。 diff --git a/docs/masters.md b/docs/masters.md index 7ede9e7..c252b97 100644 --- a/docs/masters.md +++ b/docs/masters.md @@ -76,6 +76,7 @@ next_title: 生産管理

  • 子品目(使用する部材)を選びます。
  • 必要数量を入力します。これは親1単位あたりの数量です。
  • 内外製区分と、必要なら代替部品グループを指定します。
  • +
  • 消費工程で、その部材を使う工程(工順の工程順序)を選びます。選ばなければ最終工程で使う扱いになります。
  • 明細に追加を押して行を積み上げます。
  • すべて追加したら MBOMを保存(一括置換) を押します。
  • @@ -88,6 +89,11 @@ next_title: 生産管理 MBOMは、実績入力の**バックフラッシュ**(部材の自動消費)で使われます。 バックフラッシュを使う予定があれば必ず登録してください。 +バックフラッシュは各部材を**消費工程の作業指示でだけ**引くので、組立の工程で使う部材は消費工程に組立の工程を選んでください。 + +
    +

    消費工程に工順に無い工程順序を選んだままだと、製造指図を展開できません。工順を組み直したときはMBOMの消費工程も見直してください(一覧に「(工順に無し)」と表示されます)。

    +
    --- diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 65fde13..e27369b 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -46,6 +46,8 @@ next_title: 管理者向け運用 |---|---| | 最終工程の実績には入庫先ロケーション(outputLocationId)が必要です。 | **入庫先ロケーション**を選んでから登録してください | | MBOMが未登録のためバックフラッシュできません。 | [マスタ管理](masters.html#mbom)でMBOMを登録するか、バックフラッシュのチェックを外してください | +| この工程(工程順序 ○○)で消費する予定材料が無いためバックフラッシュできません。 | この工程で使う部材はありません。バックフラッシュのチェックを外してください。部材を使う工程なら[MBOM](masters.html#mbom)の消費工程を直し、指図を作り直してください | +| MBOMの部材 '○○' の消費工程(工程順序 ○○)が品目 '○○' の工順にありません。 | [MBOM](masters.html#mbom)の消費工程か工順を直してから展開してください | | 良品数と不良数の合計は0より大きい必要があります。 | どちらかに数量を入力してください | | 状態 '○○' の作業指示には実績を記録できません。 | すでに承認済み、または取消済みです | | 状態 '○○' の作業指示は承認できません(完了済みのみ)。 | 実績を登録して「完了」にしてから承認してください | diff --git a/samples/master-csv/15_bom.csv b/samples/master-csv/15_bom.csv index 9ff4baf..158a42a 100644 --- a/samples/master-csv/15_bom.csv +++ b/samples/master-csv/15_bom.csv @@ -1,9 +1,9 @@ -ParentProductCode,ChildProductCode,QuantityPer,MakeOrBuy,AlternativeGroup,IsAlternative -FG-1000,SF-2000,1,InHouse,,false -FG-1000,RM-3002,1,InHouse,,false -FG-1000,RM-3003,1,InHouse,,false -FG-1000,RM-3004,2,InHouse,ORING-P20,false -FG-1000,RM-3007,2,InHouse,ORING-P20,true -FG-1000,RM-3005,4,InHouse,,false -FG-1000,RM-3006,0.05,InHouse,,false -SF-2000,RM-3001,1,Outsourced,,false +ParentProductCode,ChildProductCode,QuantityPer,MakeOrBuy,AlternativeGroup,IsAlternative,RoutingSequence +FG-1000,SF-2000,1,InHouse,,false,10 +FG-1000,RM-3002,1,InHouse,,false,10 +FG-1000,RM-3003,1,InHouse,,false,10 +FG-1000,RM-3004,2,InHouse,ORING-P20,false,10 +FG-1000,RM-3007,2,InHouse,ORING-P20,true,10 +FG-1000,RM-3005,4,InHouse,,false,10 +FG-1000,RM-3006,0.05,InHouse,,false,10 +SF-2000,RM-3001,1,Outsourced,,false,10 diff --git a/src/MesApp.Api/Controllers/ManufacturingOrdersController.cs b/src/MesApp.Api/Controllers/ManufacturingOrdersController.cs index 59aed62..60e3f63 100644 --- a/src/MesApp.Api/Controllers/ManufacturingOrdersController.cs +++ b/src/MesApp.Api/Controllers/ManufacturingOrdersController.cs @@ -86,7 +86,7 @@ public async Task> Get(int id, Ca order.Materials.OrderBy(m => m.ChildProduct!.Code) .Select(m => new OrderMaterialResponse( m.ChildProductId, m.ChildProduct!.Code, m.ChildProduct!.Name, - m.QuantityPer, m.PlannedQuantity, m.AlternativeGroup)).ToList()); + m.QuantityPer, m.PlannedQuantity, m.AlternativeGroup, m.RoutingSequence)).ToList()); } /// 指図登録(A-20-10-01 手動登録、B-10-10-04 突発、B-70-10-01 リワーク) diff --git a/src/MesApp.Api/Controllers/ProductsController.cs b/src/MesApp.Api/Controllers/ProductsController.cs index 64b4392..fb708f5 100644 --- a/src/MesApp.Api/Controllers/ProductsController.cs +++ b/src/MesApp.Api/Controllers/ProductsController.cs @@ -147,7 +147,7 @@ public async Task>> GetBom(int id, Cancellati .OrderBy(b => b.ChildProduct!.Code) .Select(b => new BomItemResponse( b.Id, b.ChildProductId, b.ChildProduct!.Code, b.ChildProduct!.Name, - b.QuantityPer, b.MakeOrBuy, b.AlternativeGroup, b.IsAlternative)) + b.QuantityPer, b.MakeOrBuy, b.AlternativeGroup, b.IsAlternative, b.RoutingSequence)) .ToListAsync(ct); } diff --git a/src/MesApp.Api/Localization/ApiText.en.resx b/src/MesApp.Api/Localization/ApiText.en.resx index 7cca82f..ae10f3c 100644 --- a/src/MesApp.Api/Localization/ApiText.en.resx +++ b/src/MesApp.Api/Localization/ApiText.en.resx @@ -1983,4 +1983,16 @@ A number greater than 0. Together with the quantity already shipped, it cannot exceed the instructed quantity. + + The consuming step (sequence {1}) of MBOM material '{0}' is not in the routing of item '{2}'. Correct the MBOM or the routing. + + + Cannot backflush because no planned materials are consumed at this step (sequence {0}). + + + Consuming step (sequence) + + + Sequence in the parent item's routing. Blank means the final step. Backflush consumes the material at this step + diff --git a/src/MesApp.Api/Services/ManufacturingOrderService.cs b/src/MesApp.Api/Services/ManufacturingOrderService.cs index bfacd10..6493dd2 100644 --- a/src/MesApp.Api/Services/ManufacturingOrderService.cs +++ b/src/MesApp.Api/Services/ManufacturingOrderService.cs @@ -213,6 +213,21 @@ public async Task ExpandAsync(ManufacturingOrder order, string? lo return OrderOutcome.Invalid(ApiText.T("品目 '{0}' に工順(BOP)が登録されていません。", order.Product!.Code)); } + // MBOMの消費工程は工順の工程順序で指す。MBOMと工順は別々に改訂できるため、ずれはここで止める + // (見過ごすと、どの作業指示のバックフラッシュでも引かれない部材ができる) + var bom = await db.BomItems + .Include(b => b.ChildProduct) + .Where(b => b.ParentProductId == order.ProductId) + .ToListAsync(ct); + var sequences = routing.Select(r => r.Sequence).ToHashSet(); + if (bom.FirstOrDefault(b => b.RoutingSequence is { } s && !sequences.Contains(s)) is { } orphan) + { + return OrderOutcome.Invalid(ApiText.T( + "MBOMの部材 '{0}' の消費工程(工程順序 {1})が品目 '{2}' の工順にありません。MBOMか工順を直してください。", + orphan.ChildProduct!.Code, orphan.RoutingSequence!.Value, order.Product!.Code)); + } + var finalSequence = routing[^1].Sequence; + // 産出ロット採番(手入力があれば一意性を確認して使用) if (string.IsNullOrWhiteSpace(lotNumber)) { @@ -289,10 +304,8 @@ .. controlItems } // MBOMも展開時点で予定材料として固定する。以降の投入照合(B-30-20-01)と - // バックフラッシュ(B-40-10-09)はこの予定材料を基準にする - var bom = await db.BomItems - .Where(b => b.ParentProductId == order.ProductId) - .ToListAsync(ct); + // バックフラッシュ(B-40-10-09)はこの予定材料を基準にする。 + // 消費工程が未指定の行は最終工程に解決して入れ、以降は工順の改訂に左右されないようにする foreach (var item in bom) { db.ManufacturingOrderMaterials.Add(new ManufacturingOrderMaterial @@ -303,6 +316,7 @@ .. controlItems PlannedQuantity = item.QuantityPer * order.Quantity, AlternativeGroup = item.AlternativeGroup, IsAlternative = item.IsAlternative, + RoutingSequence = item.RoutingSequence ?? finalSequence, }); } diff --git a/src/MesApp.Api/Services/MasterCsvKinds.cs b/src/MesApp.Api/Services/MasterCsvKinds.cs index cf9e31f..4cf9c6a 100644 --- a/src/MesApp.Api/Services/MasterCsvKinds.cs +++ b/src/MesApp.Api/Services/MasterCsvKinds.cs @@ -163,6 +163,7 @@ public static class MasterCsvKinds new("MakeOrBuy", "内外製区分", false, "InHouse(内製)/ Outsourced(外注)"), new("AlternativeGroup", "代替部品グループ", false, null), new("IsAlternative", "代替部品", false, "true / false。trueの行を投入するには理由の記録が必要"), + new("RoutingSequence", "消費工程(工程順序)", false, "親品目の工順の工程順序。空なら最終工程。バックフラッシュはこの工程で部材を引く"), ]), new(Routing, "工順(BOP)", false, [ diff --git a/src/MesApp.Api/Services/MasterCsvService.Import.cs b/src/MesApp.Api/Services/MasterCsvService.Import.cs index bba9cb7..1ace171 100644 --- a/src/MesApp.Api/Services/MasterCsvService.Import.cs +++ b/src/MesApp.Api/Services/MasterCsvService.Import.cs @@ -928,6 +928,7 @@ private async Task ImportBomAsync( var makeOrBuy = reader.Enum("MakeOrBuy", MakeOrBuy.InHouse, CsvEnumLabels.MakeOrBuys); var alternativeGroup = reader.Text("AlternativeGroup", null, 50); var isAlternative = reader.Bool("IsAlternative", false); + var routingSequence = reader.IntOrNull("RoutingSequence", null, 1); if (quantity is null && !reader.Failed) { reader.Fail(ApiText.T("QuantityPer(必要数量)は必須です。")); @@ -953,6 +954,7 @@ private async Task ImportBomAsync( MakeOrBuy = makeOrBuy, AlternativeGroup = alternativeGroup, IsAlternative = isAlternative, + RoutingSequence = routingSequence, }); } if (failed) diff --git a/src/MesApp.Api/Services/MasterCsvService.cs b/src/MesApp.Api/Services/MasterCsvService.cs index fdb44d9..ba6ac34 100644 --- a/src/MesApp.Api/Services/MasterCsvService.cs +++ b/src/MesApp.Api/Services/MasterCsvService.cs @@ -217,6 +217,7 @@ public async Task ExportAsync(CsvKindInfo kind, bool includeInactive, Ca { b.ParentProduct!.Code, b.ChildProduct!.Code, Num(b.QuantityPer), b.MakeOrBuy.ToString(), b.AlternativeGroup, Bool(b.IsAlternative), + b.RoutingSequence?.ToString(CultureInfo.InvariantCulture), })]; } diff --git a/src/MesApp.Api/Services/ProductStructureService.cs b/src/MesApp.Api/Services/ProductStructureService.cs index ffad404..11c6e55 100644 --- a/src/MesApp.Api/Services/ProductStructureService.cs +++ b/src/MesApp.Api/Services/ProductStructureService.cs @@ -45,6 +45,7 @@ public sealed class ProductStructureService(MesAppDbContext db, IAuditLogger aud MakeOrBuy = i.MakeOrBuy, AlternativeGroup = i.AlternativeGroup, IsAlternative = i.IsAlternative, + RoutingSequence = i.RoutingSequence, })); await db.SaveChangesAsync(ct); await auditLogger.LogAsync("Master", "Update", "Bom", productId.ToString(), diff --git a/src/MesApp.Api/Services/WorkOrderExecutionService.cs b/src/MesApp.Api/Services/WorkOrderExecutionService.cs index 1827705..f9f9346 100644 --- a/src/MesApp.Api/Services/WorkOrderExecutionService.cs +++ b/src/MesApp.Api/Services/WorkOrderExecutionService.cs @@ -343,13 +343,20 @@ public async Task> AddProductionRecordAsync( { // 消費量の基準は展開時に固定した予定材料の原単位(Spec.md 5.7)。 // 代替部品の行は除く:主材料の代わりに使う部材なので、両方を原単位ぶん引くと二重に減る。 - // 代替の投入には理由が要る(Spec.md 3.9)ため、代替部品は手動の部材投入で理由とともに記録する + // 代替の投入には理由が要る(Spec.md 3.9)ため、代替部品は手動の部材投入で理由とともに記録する。 + // 引くのはこの作業指示の工程で消費する部材だけ。指図の全部材を引くと、工程ごとに + // バックフラッシュしたとき工程数ぶん二重に減る。消費工程が null の行(項目追加前の指図)は最終工程で引く + var sequence = workOrder.RoutingSequence; var bom = await db.ManufacturingOrderMaterials - .Where(m => m.ManufacturingOrderId == workOrder.ManufacturingOrderId && !m.IsAlternative) + .Where(m => m.ManufacturingOrderId == workOrder.ManufacturingOrderId && !m.IsAlternative + && (m.RoutingSequence == sequence || (m.RoutingSequence == null && isFinalStep))) .ToListAsync(ct); if (bom.Count == 0) { - return Outcome.Invalid(ApiText.T("予定材料が未登録(展開時にMBOMが未登録)のためバックフラッシュできません。")); + return Outcome.Invalid( + await db.ManufacturingOrderMaterials.AnyAsync(m => m.ManufacturingOrderId == workOrder.ManufacturingOrderId, ct) + ? ApiText.T("この工程(工程順序 {0})で消費する予定材料が無いためバックフラッシュできません。", sequence) + : ApiText.T("予定材料が未登録(展開時にMBOMが未登録)のためバックフラッシュできません。")); } var totalProduced = request.GoodQuantity + request.DefectQuantity; foreach (var bomItem in bom) diff --git a/src/MesApp.Client.Web/Pages/ManufacturingOrderDetail.razor b/src/MesApp.Client.Web/Pages/ManufacturingOrderDetail.razor index 0d22415..1afcaea 100644 --- a/src/MesApp.Client.Web/Pages/ManufacturingOrderDetail.razor +++ b/src/MesApp.Client.Web/Pages/ManufacturingOrderDetail.razor @@ -105,7 +105,7 @@ else

    @L["予定材料(展開時のMBOMで確定)"]

    - + @foreach (var material in _detail.Materials) @@ -115,6 +115,7 @@ else + } diff --git a/src/MesApp.Client.Web/Pages/Masters/Products/ProductBomEditor.razor b/src/MesApp.Client.Web/Pages/Masters/Products/ProductBomEditor.razor index 3deccf5..efddcd1 100644 --- a/src/MesApp.Client.Web/Pages/Masters/Products/ProductBomEditor.razor +++ b/src/MesApp.Client.Web/Pages/Masters/Products/ProductBomEditor.razor @@ -5,7 +5,7 @@

    @L["{0} {1} の MBOM(A-40-10)", Product.Code, Product.Name]

    @L["品目"]@L["原単位"]@L["予定数量"]@L["代替部品グループ"]
    @L["品目"]@L["原単位"]@L["予定数量"]@L["代替部品グループ"]@L["消費工程"]
    @material.QuantityPer @material.PlannedQuantity @(material.AlternativeGroup ?? "-")@(material.RoutingSequence?.ToString() ?? L["最終工程"].Value)
    - + @foreach (var line in _lines) { @@ -15,6 +15,7 @@ + } @@ -54,6 +55,17 @@ @L["代替部品(主材料でない)"] + @* バックフラッシュはこの工程の作業指示で部材を引く(B-40-10-09) *@ +
    + + +
    @@ -73,6 +85,7 @@ [Parameter] public EventCallback OnSaved { get; set; } private readonly List _lines = []; + private List _routing = []; private int _loadedProductId; private int _childId; @@ -80,6 +93,7 @@ private MakeOrBuy _makeOrBuy = MakeOrBuy.InHouse; private string? _altGroup; private bool _isAlternative; + private int _routingSequence; private string? _error; private string? _message; @@ -101,7 +115,9 @@ var bom = await Http.GetFromJsonAsync>($"api/products/{Product.Id}/bom") ?? []; _lines.AddRange(bom.Select(b => new BomItemRequest(b.ChildProductId, b.QuantityPer, b.MakeOrBuy, b.AlternativeGroup, - b.IsAlternative))); + b.IsAlternative, b.RoutingSequence))); + // 消費工程の選択肢。工順は隣の編集欄で直せるため、MBOMを読み直すたびに取り直す + _routing = await Http.GetFromJsonAsync>($"api/products/{Product.Id}/routing") ?? []; // 親から呼ばれたときはパラメータが変わらないため、自分で再描画を要求する StateHasChanged(); } @@ -115,11 +131,20 @@ } _error = null; _lines.Add(new BomItemRequest(_childId, _quantity, _makeOrBuy, - string.IsNullOrWhiteSpace(_altGroup) ? null : _altGroup, _isAlternative)); + string.IsNullOrWhiteSpace(_altGroup) ? null : _altGroup, _isAlternative, + _routingSequence == 0 ? null : _routingSequence)); _childId = 0; _isAlternative = false; } + /// 消費工程の表示。工順に無い工程順序は指図の展開で拒否されるため、ここで目立たせる + private string StepLabel(int? sequence) => sequence switch + { + null => L["最終工程"], + { } s when _routing.FirstOrDefault(r => r.Sequence == s) is { } step => $"{s} {step.ProcessName}", + { } s => L["{0}(工順に無し)", s], + }; + private async Task SaveAsync() { _busy = true; diff --git a/src/MesApp.Client.Web/Shared/UiText.en.resx b/src/MesApp.Client.Web/Shared/UiText.en.resx index e307d34..1985960 100644 --- a/src/MesApp.Client.Web/Shared/UiText.en.resx +++ b/src/MesApp.Client.Web/Shared/UiText.en.resx @@ -4155,4 +4155,16 @@ production date + product code + process code + work center code + + Consuming step + + + Final step + + + Final step (not specified) + + + {0} (not in routing) + diff --git a/src/MesApp.Core/Contracts/Masters/MasterContracts.cs b/src/MesApp.Core/Contracts/Masters/MasterContracts.cs index 83d5416..cfedc24 100644 --- a/src/MesApp.Core/Contracts/Masters/MasterContracts.cs +++ b/src/MesApp.Core/Contracts/Masters/MasterContracts.cs @@ -28,12 +28,14 @@ public record BomItemRequest( MakeOrBuy MakeOrBuy, string? AlternativeGroup, /// 代替部品か(同一グループ内の主材料でない行。投入時に理由の記録を求める) - bool IsAlternative = false); + bool IsAlternative = false, + /// 消費する工程の工程順序(未指定なら最終工程。バックフラッシュはこの工程で引く) + [Range(1, int.MaxValue)] int? RoutingSequence = null); public record BomItemResponse( int Id, int ChildProductId, string ChildProductCode, string ChildProductName, decimal QuantityPer, MakeOrBuy MakeOrBuy, string? AlternativeGroup, - bool IsAlternative = false); + bool IsAlternative = false, int? RoutingSequence = null); // ---- 工程(Process)---- diff --git a/src/MesApp.Core/Contracts/Production/ProductionContracts.cs b/src/MesApp.Core/Contracts/Production/ProductionContracts.cs index 187efd4..ad62071 100644 --- a/src/MesApp.Core/Contracts/Production/ProductionContracts.cs +++ b/src/MesApp.Core/Contracts/Production/ProductionContracts.cs @@ -28,7 +28,8 @@ public record ManufacturingOrderResponse( /// 指図の予定材料(展開時にMBOMから固定。Spec.md 5.7) public record OrderMaterialResponse( int ChildProductId, string ProductCode, string ProductName, - decimal QuantityPer, decimal PlannedQuantity, string? AlternativeGroup); + decimal QuantityPer, decimal PlannedQuantity, string? AlternativeGroup, + int? RoutingSequence = null); public record ManufacturingOrderDetailResponse( ManufacturingOrderResponse Order, diff --git a/src/MesApp.Core/Entities/Masters.cs b/src/MesApp.Core/Entities/Masters.cs index b7292a4..1f635b4 100644 --- a/src/MesApp.Core/Entities/Masters.cs +++ b/src/MesApp.Core/Entities/Masters.cs @@ -61,6 +61,13 @@ public class BomItem /// 代替部品の投入には理由の記録を求める(Spec.md 3.9 部材投入の照合) /// public bool IsAlternative { get; set; } + + /// + /// この部材を消費する工程(親品目の工順の工程順序 。B-40-10-09)。 + /// 未設定なら最終工程で消費する。工順は一括置換で行が作り直されるため、IDではなく工程順序で指す。 + /// 工順に無い工程順序は指図の展開時に拒否する(MBOMと工順はどちらを先に登録してもよいため、登録時には照合しない) + /// + public int? RoutingSequence { get; set; } } /// 工程マスタ(Spec.md 5.1 Process) diff --git a/src/MesApp.Core/Entities/Production.cs b/src/MesApp.Core/Entities/Production.cs index b0fb782..fcabb75 100644 --- a/src/MesApp.Core/Entities/Production.cs +++ b/src/MesApp.Core/Entities/Production.cs @@ -75,6 +75,13 @@ public class ManufacturingOrderMaterial /// 代替部品か(展開時点のMBOMの値。投入時に理由の記録を求める) public bool IsAlternative { get; set; } + + /// + /// この部材を消費する工程順序(展開時点のMBOMの値。未設定の行は展開時に最終工程へ解決して入れる)。 + /// バックフラッシュはこの工程の作業指示でだけ消費する。 + /// null は本項目の追加前に展開した指図で、最終工程で消費したものとして扱う + /// + public int? RoutingSequence { get; set; } } /// 作業指示(Spec.md 5.2 WorkOrder。製造指図×工程。B-10) diff --git a/src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.Designer.cs b/src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.Designer.cs new file mode 100644 index 0000000..7cf7afa --- /dev/null +++ b/src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.Designer.cs @@ -0,0 +1,4753 @@ +// +using System; +using MesApp.Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace MesApp.Infrastructure.Migrations +{ + [DbContext(typeof(MesAppDbContext))] + [Migration("20260922224608_AddBomItemRoutingSequence")] + partial class AddBomItemRoutingSequence + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.10"); + + modelBuilder.Entity("MesApp.Core.Entities.AppUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Department") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("MustChangePassword") + .HasColumnType("INTEGER"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("ShiftId") + .HasColumnType("INTEGER"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("WorkCenterId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("ShiftId"); + + b.HasIndex("WorkCenterId"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Detail") + .HasColumnType("TEXT"); + + b.Property("IpAddress") + .HasColumnType("TEXT"); + + b.Property("RecordedOn") + .HasColumnType("TEXT"); + + b.Property("TargetId") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("TargetType") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("UserName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RecordedOn"); + + b.HasIndex("Timestamp"); + + b.HasIndex("UserId"); + + b.HasIndex("Category", "Action"); + + b.HasIndex("TargetType", "TargetId"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.BomItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AlternativeGroup") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ChildProductId") + .HasColumnType("INTEGER"); + + b.Property("IsAlternative") + .HasColumnType("INTEGER"); + + b.Property("MakeOrBuy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ParentProductId") + .HasColumnType("INTEGER"); + + b.Property("QuantityPer") + .HasColumnType("TEXT"); + + b.Property("RoutingSequence") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChildProductId"); + + b.HasIndex("ParentProductId", "ChildProductId") + .IsUnique(); + + b.ToTable("BomItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Checklist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Checklists"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChecklistId") + .HasColumnType("INTEGER"); + + b.Property("IsRequired") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .HasColumnType("INTEGER"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.ToTable("ChecklistItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChecklistId") + .HasColumnType("INTEGER"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("PerformedAt") + .HasColumnType("TEXT"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ChecklistRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistResultItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChecklistItemId") + .HasColumnType("INTEGER"); + + b.Property("ChecklistRecordId") + .HasColumnType("INTEGER"); + + b.Property("IsChecked") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistItemId"); + + b.HasIndex("ChecklistRecordId"); + + b.ToTable("ChecklistResultItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ControlItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("LowerLimit") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("TargetProcessId") + .HasColumnType("INTEGER"); + + b.Property("TargetProductId") + .HasColumnType("INTEGER"); + + b.Property("TargetValue") + .HasColumnType("TEXT"); + + b.Property("Unit") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("UpperLimit") + .HasColumnType("TEXT"); + + b.Property("Version") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("TargetProcessId"); + + b.HasIndex("TargetProductId"); + + b.ToTable("ControlItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.DefectReason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("DefectReasons"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AssetNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("MaintenanceParts") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("MaintenanceThreshold") + .HasColumnType("TEXT"); + + b.Property("MaintenanceType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Site") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkCenterId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AssetNo") + .IsUnique(); + + b.HasIndex("WorkCenterId"); + + b.ToTable("Equipments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("EndedAt") + .HasColumnType("TEXT"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("RecordedByUserId") + .HasColumnType("TEXT"); + + b.Property("StartedAt") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("StopCause") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("EquipmentLogs"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentPart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("QuantityPer") + .HasPrecision(18, 4) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("EquipmentId", "ProductId") + .IsUnique(); + + b.ToTable("EquipmentParts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDevice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CalibratedOn") + .HasColumnType("TEXT"); + + b.Property("CalibrationCycleDays") + .HasColumnType("INTEGER"); + + b.Property("CalibrationDueOn") + .HasColumnType("TEXT"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Location") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("SerialNo") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("InspectionDevices"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDeviceCalibration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CalibratedOn") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("InspectionDeviceId") + .HasColumnType("INTEGER"); + + b.Property("NextDueOn") + .HasColumnType("TEXT"); + + b.Property("PerformedByUserId") + .HasColumnType("TEXT"); + + b.Property("Result") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("InspectionDeviceId", "CalibratedOn"); + + b.ToTable("InspectionDeviceCalibrations"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("LowerLimit") + .HasColumnType("TEXT"); + + b.Property("Method") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("SamplingCount") + .HasColumnType("INTEGER"); + + b.Property("StandardValue") + .HasColumnType("TEXT"); + + b.Property("TargetProcessId") + .HasColumnType("INTEGER"); + + b.Property("TargetProductId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("UpperLimit") + .HasColumnType("TEXT"); + + b.Property("Version") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("TargetProcessId"); + + b.HasIndex("TargetProductId"); + + b.ToTable("InspectionItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApprovedAt") + .HasColumnType("TEXT"); + + b.Property("ApprovedByUserId") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("JudgedAt") + .HasColumnType("TEXT"); + + b.Property("JudgedByUserId") + .HasColumnType("TEXT"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OverallJudgment") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("RequestedByUserId") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("TargetLotId") + .HasColumnType("INTEGER"); + + b.Property("TargetWorkOrderId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("RequestedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("TargetLotId"); + + b.HasIndex("TargetWorkOrderId"); + + b.ToTable("InspectionOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrderItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("InspectionItemId") + .HasColumnType("INTEGER"); + + b.Property("InspectionOrderId") + .HasColumnType("INTEGER"); + + b.Property("ItemCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ItemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ItemVersion") + .HasColumnType("INTEGER"); + + b.Property("LowerLimit") + .HasColumnType("TEXT"); + + b.Property("Method") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("SamplingCount") + .HasColumnType("INTEGER"); + + b.Property("StandardValue") + .HasColumnType("TEXT"); + + b.Property("UpperLimit") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InspectionItemId"); + + b.HasIndex("InspectionOrderId", "InspectionItemId") + .IsUnique(); + + b.ToTable("InspectionOrderItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionNote") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("InspectedAt") + .HasColumnType("TEXT"); + + b.Property("InspectedByUserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("InspectionDeviceId") + .HasColumnType("INTEGER"); + + b.Property("InspectionItemId") + .HasColumnType("INTEGER"); + + b.Property("InspectionOrderId") + .HasColumnType("INTEGER"); + + b.Property("Judgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("MeasuredValue") + .HasColumnType("TEXT"); + + b.Property("SampleNo") + .HasColumnType("INTEGER"); + + b.Property("TextValue") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InspectedByUserId"); + + b.HasIndex("InspectionDeviceId"); + + b.HasIndex("InspectionItemId"); + + b.HasIndex("InspectionOrderId"); + + b.ToTable("InspectionResults"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResultCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AfterJudgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("AfterMeasuredValue") + .HasColumnType("TEXT"); + + b.Property("AfterTextValue") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("BeforeJudgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("BeforeMeasuredValue") + .HasColumnType("TEXT"); + + b.Property("BeforeTextValue") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("CorrectedAt") + .HasColumnType("TEXT"); + + b.Property("CorrectedByUserId") + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.Property("InspectionOrderId") + .HasColumnType("INTEGER"); + + b.Property("InspectionResultId") + .HasColumnType("INTEGER"); + + b.Property("Reason") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CorrectedByUserId"); + + b.HasIndex("InspectionResultId"); + + b.HasIndex("InspectionOrderId", "Id"); + + b.ToTable("InspectionResultCorrections"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryStock", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("LocationId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId", "LocationId") + .IsUnique(); + + b.HasIndex("ProductId", "LocationId"); + + b.ToTable("InventoryStocks"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("FromLocationId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("PerformedByUserId") + .HasColumnType("TEXT"); + + b.Property("PickingOrderId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("ShippingOrderId") + .HasColumnType("INTEGER"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("ToLocationId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("FromLocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("Timestamp"); + + b.HasIndex("ToLocationId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("InventoryTransactions"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AreaType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("ShelfNo") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("WorkCenterId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("WorkCenterId"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Lot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("ExpiresOn") + .HasColumnType("TEXT"); + + b.Property("Grade") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("InitialQuantity") + .HasColumnType("TEXT"); + + b.Property("LotNumber") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("TEXT"); + + b.Property("ManufacturedOn") + .HasColumnType("TEXT"); + + b.Property("OriginType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ParentLotId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("SourceWorkOrderId") + .HasColumnType("INTEGER"); + + b.Property("StockStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LotNumber") + .IsUnique(); + + b.HasIndex("ParentLotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SourceWorkOrderId"); + + b.ToTable("Lots"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotGenealogy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChildLotId") + .HasColumnType("INTEGER"); + + b.Property("OccurredAt") + .HasColumnType("TEXT"); + + b.Property("ParentLotId") + .HasColumnType("INTEGER"); + + b.Property("PerformedByUserId") + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("RelationType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChildLotId"); + + b.HasIndex("ParentLotId"); + + b.ToTable("LotGenealogies"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotStatusHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChangedAt") + .HasColumnType("TEXT"); + + b.Property("ChangedByUserId") + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.Property("FromStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("InspectionOrderId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("NonconformanceReportId") + .HasColumnType("INTEGER"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ToStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LotId", "Id"); + + b.ToTable("LotStatusHistories"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedByUserId") + .HasColumnType("TEXT"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("MaintenancePlanId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ProcedureId") + .HasColumnType("INTEGER"); + + b.Property("RequestType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ScheduledDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ToolId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByUserId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("MaintenancePlanId"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("ProcedureId"); + + b.HasIndex("Status"); + + b.HasIndex("ToolId"); + + b.ToTable("MaintenanceOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenancePlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedByUserId") + .HasColumnType("TEXT"); + + b.Property("CycleDays") + .HasColumnType("INTEGER"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("PlanYear") + .HasColumnType("INTEGER"); + + b.Property("ScheduledDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId", "PlanYear"); + + b.ToTable("MaintenancePlans"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceProcedure", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("ProcedureNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Steps") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("TargetEquipmentId") + .HasColumnType("INTEGER"); + + b.Property("TargetToolId") + .HasColumnType("INTEGER"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Version") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ProcedureNo") + .IsUnique(); + + b.HasIndex("TargetEquipmentId"); + + b.HasIndex("TargetToolId"); + + b.ToTable("MaintenanceProcedures"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("EndedAt") + .HasColumnType("TEXT"); + + b.Property("MaintenanceOrderId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("PartsUsed") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Result") + .HasMaxLength(2000) + .HasColumnType("TEXT"); + + b.Property("StartedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MaintenanceOrderId"); + + b.HasIndex("PerformedByUserId"); + + b.ToTable("MaintenanceRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecordPart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LocationId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("MaintenanceRecordId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasPrecision(18, 4) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("MaintenanceRecordId"); + + b.HasIndex("ProductId"); + + b.ToTable("MaintenanceRecordParts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApprovedAt") + .HasColumnType("TEXT"); + + b.Property("ApprovedByUserId") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedByUserId") + .HasColumnType("TEXT"); + + b.Property("DueDate") + .HasColumnType("TEXT"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OrderType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("OutputLotId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("SourceOrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("OutputLotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SourceOrderId"); + + b.HasIndex("Status"); + + b.ToTable("ManufacturingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrderMaterial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AlternativeGroup") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ChildProductId") + .HasColumnType("INTEGER"); + + b.Property("IsAlternative") + .HasColumnType("INTEGER"); + + b.Property("ManufacturingOrderId") + .HasColumnType("INTEGER"); + + b.Property("PlannedQuantity") + .HasColumnType("TEXT"); + + b.Property("QuantityPer") + .HasColumnType("TEXT"); + + b.Property("RoutingSequence") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChildProductId"); + + b.HasIndex("ManufacturingOrderId", "ChildProductId") + .IsUnique(); + + b.ToTable("ManufacturingOrderMaterials"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaterialConsumption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConsumedAt") + .HasColumnType("TEXT"); + + b.Property("IsSubstitute") + .HasColumnType("INTEGER"); + + b.Property("LocationId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("Method") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("RecordedByUserId") + .HasColumnType("TEXT"); + + b.Property("SubstituteReason") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("MaterialConsumptions"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NonconformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ActionCompletedAt") + .HasColumnType("TEXT"); + + b.Property("ActionCompletedByUserId") + .HasColumnType("TEXT"); + + b.Property("ActionInstructedAt") + .HasColumnType("TEXT"); + + b.Property("ActionInstructedByUserId") + .HasColumnType("TEXT"); + + b.Property("ActionInstruction") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("ActionRecord") + .HasMaxLength(2000) + .HasColumnType("TEXT"); + + b.Property("ApprovedAt") + .HasColumnType("TEXT"); + + b.Property("ApprovedByUserId") + .HasColumnType("TEXT"); + + b.Property("CauseCategory") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("CauseDetail") + .HasMaxLength(2000) + .HasColumnType("TEXT"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("InspectionOrderId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("ReportNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ReportedByUserId") + .HasColumnType("TEXT"); + + b.Property("ReworkOrderId") + .HasColumnType("INTEGER"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InspectionOrderId"); + + b.HasIndex("LotId"); + + b.HasIndex("ReportNo") + .IsUnique(); + + b.HasIndex("ReportedByUserId"); + + b.HasIndex("ReworkOrderId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("NonconformanceReports"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NumberSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastValue") + .HasColumnType("INTEGER"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Prefix") + .IsUnique(); + + b.ToTable("NumberSequences"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LocationId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("PickingOrderId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("PickingOrderId"); + + b.HasIndex("ProductId"); + + b.ToTable("PickingLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedByUserId") + .HasColumnType("TEXT"); + + b.Property("ExecutedAt") + .HasColumnType("TEXT"); + + b.Property("ExecutedByUserId") + .HasColumnType("TEXT"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ShippingOrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("ShippingOrderId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("PickingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProcessMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Processes", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DefaultLocationId") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Specification") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("StandardDefectRate") + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Unit") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("DefaultLocationId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDataRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("IsDeviation") + .HasColumnType("INTEGER"); + + b.Property("Item") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("NumericValue") + .HasColumnType("TEXT"); + + b.Property("RecordedAt") + .HasColumnType("TEXT"); + + b.Property("RecordedByUserId") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("WorkOrderControlItemId") + .HasColumnType("INTEGER"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("WorkOrderControlItemId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ProductionDataRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDefect", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DefectReasonId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("ProductionRecordId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DefectReasonId"); + + b.HasIndex("ProductionRecordId"); + + b.ToTable("ProductionDefects"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BusinessDate") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("PlannedQuantity") + .HasColumnType("TEXT"); + + b.Property("ProcessId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("WorkCenterId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ProcessId"); + + b.HasIndex("ProductId"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("BusinessDate", "ProductId", "ProcessId", "WorkCenterId") + .IsUnique(); + + b.ToTable("ProductionPlans"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApprovedAt") + .HasColumnType("TEXT"); + + b.Property("ApprovedByUserId") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DefectQuantity") + .HasColumnType("TEXT"); + + b.Property("EndedAt") + .HasColumnType("TEXT"); + + b.Property("GoodQuantity") + .HasColumnType("TEXT"); + + b.Property("OutputLocationId") + .HasColumnType("INTEGER"); + + b.Property("OutputLotId") + .HasColumnType("INTEGER"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ReworkQuantity") + .HasColumnType("TEXT"); + + b.Property("ScrapQuantity") + .HasColumnType("TEXT"); + + b.Property("ShiftId") + .HasColumnType("INTEGER"); + + b.Property("StartedAt") + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OutputLotId"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("ShiftId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ProductionRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecordCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AfterDefectQuantity") + .HasColumnType("TEXT"); + + b.Property("AfterGoodQuantity") + .HasColumnType("TEXT"); + + b.Property("AfterReworkQuantity") + .HasColumnType("TEXT"); + + b.Property("AfterScrapQuantity") + .HasColumnType("TEXT"); + + b.Property("BeforeDefectQuantity") + .HasColumnType("TEXT"); + + b.Property("BeforeGoodQuantity") + .HasColumnType("TEXT"); + + b.Property("BeforeReworkQuantity") + .HasColumnType("TEXT"); + + b.Property("BeforeScrapQuantity") + .HasColumnType("TEXT"); + + b.Property("CorrectedAt") + .HasColumnType("TEXT"); + + b.Property("CorrectedByUserId") + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.Property("ProductionRecordId") + .HasColumnType("INTEGER"); + + b.Property("Reason") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CorrectedByUserId"); + + b.HasIndex("ProductionRecordId"); + + b.HasIndex("WorkOrderId", "Id"); + + b.ToTable("ProductionRecordCorrections"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("ExpiresAt") + .HasColumnType("TEXT"); + + b.Property("RevokedAt") + .HasColumnType("TEXT"); + + b.Property("TokenHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("TokenHash") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChecklistId") + .HasColumnType("INTEGER"); + + b.Property("ControlItems") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("ProcessId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("RequiredSkillId") + .HasColumnType("INTEGER"); + + b.Property("Sequence") + .HasColumnType("INTEGER"); + + b.Property("StandardSetupMinutes") + .HasColumnType("TEXT"); + + b.Property("StandardWorkMinutes") + .HasColumnType("TEXT"); + + b.Property("ToolId") + .HasColumnType("INTEGER"); + + b.Property("WorkCenterId") + .HasColumnType("INTEGER"); + + b.Property("WorkProcedureId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("ProcessId"); + + b.HasIndex("RequiredSkillId"); + + b.HasIndex("ToolId"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("WorkProcedureId"); + + b.HasIndex("ProductId", "Sequence") + .IsUnique(); + + b.ToTable("Routings"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RoutingEquipment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("RoutingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("RoutingId", "EquipmentId") + .IsUnique(); + + b.ToTable("RoutingEquipments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SampleStorage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClosedByUserId") + .HasColumnType("TEXT"); + + b.Property("ClosedOn") + .HasColumnType("TEXT"); + + b.Property("CollectedByUserId") + .HasColumnType("TEXT"); + + b.Property("CollectedOn") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("InspectionOrderId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasPrecision(18, 4) + .HasColumnType("TEXT"); + + b.Property("RetainUntil") + .HasColumnType("TEXT"); + + b.Property("SampleNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("StorageLocationId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InspectionOrderId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SampleNo") + .IsUnique(); + + b.HasIndex("StorageLocationId"); + + b.HasIndex("Status", "RetainUntil"); + + b.ToTable("SampleStorages"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SetupRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AbnormalityNote") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("EndedAt") + .HasColumnType("TEXT"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartedAt") + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("SetupRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Shift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("EndTime") + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("StartTime") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Shifts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShipmentJudgment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApprovedAt") + .HasColumnType("TEXT"); + + b.Property("ApprovedByUserId") + .HasColumnType("TEXT"); + + b.Property("JudgedAt") + .HasColumnType("TEXT"); + + b.Property("JudgedByUserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("JudgmentNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("Result") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ShippingOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("JudgedByUserId"); + + b.HasIndex("JudgmentNo") + .IsUnique(); + + b.HasIndex("LotId"); + + b.HasIndex("ShippingOrderId"); + + b.ToTable("ShipmentJudgments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("ShippedQuantity") + .HasColumnType("TEXT"); + + b.Property("ShippingOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("ShippingOrderId"); + + b.ToTable("ShippingLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedByUserId") + .HasColumnType("TEXT"); + + b.Property("Destination") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("PlannedDate") + .HasColumnType("TEXT"); + + b.Property("ShippedAt") + .HasColumnType("TEXT"); + + b.Property("ShippedByUserId") + .HasColumnType("TEXT"); + + b.Property("ShippingNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ShippingNo") + .IsUnique(); + + b.ToTable("ShippingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SkillMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("RequiresExpiry") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedByUserId") + .HasColumnType("TEXT"); + + b.Property("FinalizedAt") + .HasColumnType("TEXT"); + + b.Property("FinalizedByUserId") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("StocktakeNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("TargetLocationId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("StocktakeNo") + .IsUnique(); + + b.HasIndex("TargetLocationId"); + + b.ToTable("Stocktakes"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.StocktakeLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CountedQuantity") + .HasColumnType("TEXT"); + + b.Property("IsAdjusted") + .HasColumnType("INTEGER"); + + b.Property("LocationId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("StocktakeId") + .HasColumnType("INTEGER"); + + b.Property("TheoreticalQuantity") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("StocktakeId"); + + b.ToTable("StocktakeLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Tool", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("LifeResetAt") + .HasColumnType("TEXT"); + + b.Property("LifeThresholdCount") + .HasColumnType("INTEGER"); + + b.Property("LifeThresholdHours") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ToolType") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Tools"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolIssue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AllocatedAt") + .HasColumnType("TEXT"); + + b.Property("AllocatedByUserId") + .HasColumnType("TEXT"); + + b.Property("IssuedAt") + .HasColumnType("TEXT"); + + b.Property("IssuedToUserId") + .HasColumnType("TEXT"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("ReturnedAt") + .HasColumnType("TEXT"); + + b.Property("ReturnedByUserId") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("ToolId") + .HasColumnType("INTEGER"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("IssuedToUserId"); + + b.HasIndex("WorkOrderId"); + + b.HasIndex("ToolId", "Status"); + + b.ToTable("ToolIssues"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolUsage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RecordedAt") + .HasColumnType("TEXT"); + + b.Property("RecordedByUserId") + .HasColumnType("TEXT"); + + b.Property("ToolId") + .HasColumnType("INTEGER"); + + b.Property("UsageCount") + .HasColumnType("INTEGER"); + + b.Property("UsageHours") + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ToolId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ToolUsages"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TransferOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedByUserId") + .HasColumnType("TEXT"); + + b.Property("ExecutedAt") + .HasColumnType("TEXT"); + + b.Property("ExecutedByUserId") + .HasColumnType("TEXT"); + + b.Property("FromLocationId") + .HasColumnType("INTEGER"); + + b.Property("LotId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ToLocationId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("FromLocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("Status"); + + b.HasIndex("ToLocationId"); + + b.ToTable("TransferOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TroubleReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("EquipmentId") + .HasColumnType("INTEGER"); + + b.Property("OccurredAt") + .HasColumnType("TEXT"); + + b.Property("ReportedByUserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ResponseHistory") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("ReportedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("TroubleReports"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.UserSkill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AcquiredOn") + .HasColumnType("TEXT"); + + b.Property("ExpiresOn") + .HasColumnType("TEXT"); + + b.Property("SkillId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("UserId", "SkillId") + .IsUnique(); + + b.ToTable("UserSkills"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkCenter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("Level") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.ToTable("WorkCenters"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AssignedEquipmentId") + .HasColumnType("INTEGER"); + + b.Property("AssignedUserId") + .HasColumnType("TEXT"); + + b.Property("ControlItems") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DispatchOrder") + .HasColumnType("INTEGER"); + + b.Property("ManufacturingOrderId") + .HasColumnType("INTEGER"); + + b.Property("PlannedQuantity") + .HasColumnType("TEXT"); + + b.Property("ProcessId") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("RequiredSkillId") + .HasColumnType("INTEGER"); + + b.Property("RoutingChecklistId") + .HasColumnType("INTEGER"); + + b.Property("RoutingSequence") + .HasColumnType("INTEGER"); + + b.Property("StandardSetupMinutes") + .HasColumnType("TEXT"); + + b.Property("StandardWorkMinutes") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkCenterId") + .HasColumnType("INTEGER"); + + b.Property("WorkOrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("WorkProcedureId") + .HasColumnType("INTEGER"); + + b.Property("WorkProcedureVersion") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AssignedEquipmentId"); + + b.HasIndex("AssignedUserId"); + + b.HasIndex("ManufacturingOrderId"); + + b.HasIndex("ProcessId"); + + b.HasIndex("ProductId"); + + b.HasIndex("RequiredSkillId"); + + b.HasIndex("RoutingChecklistId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("WorkOrderNo") + .IsUnique(); + + b.HasIndex("WorkProcedureId"); + + b.ToTable("WorkOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderControlItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ControlItemId") + .HasColumnType("INTEGER"); + + b.Property("ItemCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ItemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ItemVersion") + .HasColumnType("INTEGER"); + + b.Property("LowerLimit") + .HasColumnType("TEXT"); + + b.Property("TargetValue") + .HasColumnType("TEXT"); + + b.Property("Unit") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("UpperLimit") + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ControlItemId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("WorkOrderControlItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderStatusHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChangedAt") + .HasColumnType("TEXT"); + + b.Property("ChangedByUserId") + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.Property("FromStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("ToStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChangedByUserId"); + + b.HasIndex("WorkOrderId", "Id"); + + b.ToTable("WorkOrderStatusHistories"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkProcedure", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .HasColumnType("INTEGER"); + + b.Property("ProcedureNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Reference") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("Steps") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Version") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ProcedureNo") + .IsUnique(); + + b.ToTable("WorkProcedures"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkTimeRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EndedAt") + .HasColumnType("TEXT"); + + b.Property("IndirectCategory") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("StartedAt") + .HasColumnType("TEXT"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("WorkOrderId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("WorkOrderId"); + + b.HasIndex("UserId", "StartedAt"); + + b.ToTable("WorkTimeRecords"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.AppUser", b => + { + b.HasOne("MesApp.Core.Entities.Shift", "Shift") + .WithMany() + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Shift"); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.BomItem", b => + { + b.HasOne("MesApp.Core.Entities.Product", "ChildProduct") + .WithMany() + .HasForeignKey("ChildProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "ParentProduct") + .WithMany() + .HasForeignKey("ParentProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChildProduct"); + + b.Navigation("ParentProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistItem", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", null) + .WithMany("Items") + .HasForeignKey("ChecklistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", "Checklist") + .WithMany() + .HasForeignKey("ChecklistId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Checklist"); + + b.Navigation("Equipment"); + + b.Navigation("PerformedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistResultItem", b => + { + b.HasOne("MesApp.Core.Entities.ChecklistItem", "ChecklistItem") + .WithMany() + .HasForeignKey("ChecklistItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ChecklistRecord", null) + .WithMany("Results") + .HasForeignKey("ChecklistRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChecklistItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ControlItem", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "TargetProcess") + .WithMany() + .HasForeignKey("TargetProcessId"); + + b.HasOne("MesApp.Core.Entities.Product", "TargetProduct") + .WithMany() + .HasForeignKey("TargetProductId"); + + b.Navigation("TargetProcess"); + + b.Navigation("TargetProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentLog", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Equipment"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentPart", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany("Parts") + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Equipment"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDeviceCalibration", b => + { + b.HasOne("MesApp.Core.Entities.InspectionDevice", "InspectionDevice") + .WithMany() + .HasForeignKey("InspectionDeviceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("InspectionDevice"); + + b.Navigation("PerformedBy"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionItem", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "TargetProcess") + .WithMany() + .HasForeignKey("TargetProcessId"); + + b.HasOne("MesApp.Core.Entities.Product", "TargetProduct") + .WithMany() + .HasForeignKey("TargetProductId"); + + b.Navigation("TargetProcess"); + + b.Navigation("TargetProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "RequestedBy") + .WithMany() + .HasForeignKey("RequestedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Lot", "TargetLot") + .WithMany() + .HasForeignKey("TargetLotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "TargetWorkOrder") + .WithMany() + .HasForeignKey("TargetWorkOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("RequestedBy"); + + b.Navigation("TargetLot"); + + b.Navigation("TargetWorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrderItem", b => + { + b.HasOne("MesApp.Core.Entities.InspectionItem", "InspectionItem") + .WithMany() + .HasForeignKey("InspectionItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionOrder", null) + .WithMany("Items") + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InspectionItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResult", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "InspectedBy") + .WithMany() + .HasForeignKey("InspectedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionDevice", "InspectionDevice") + .WithMany() + .HasForeignKey("InspectionDeviceId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.InspectionItem", "InspectionItem") + .WithMany() + .HasForeignKey("InspectionItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionOrder", null) + .WithMany("Results") + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InspectedBy"); + + b.Navigation("InspectionDevice"); + + b.Navigation("InspectionItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResultCorrection", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CorrectedBy") + .WithMany() + .HasForeignKey("CorrectedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.InspectionResult", "InspectionResult") + .WithMany() + .HasForeignKey("InspectionResultId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CorrectedBy"); + + b.Navigation("InspectionResult"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryStock", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryTransaction", b => + { + b.HasOne("MesApp.Core.Entities.Location", "FromLocation") + .WithMany() + .HasForeignKey("FromLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "ToLocation") + .WithMany() + .HasForeignKey("ToLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("FromLocation"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("ToLocation"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Location", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Lot", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "ParentLot") + .WithMany() + .HasForeignKey("ParentLotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "SourceWorkOrder") + .WithMany() + .HasForeignKey("SourceWorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ParentLot"); + + b.Navigation("Product"); + + b.Navigation("SourceWorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotGenealogy", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "ChildLot") + .WithMany() + .HasForeignKey("ChildLotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "ParentLot") + .WithMany() + .HasForeignKey("ParentLotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ChildLot"); + + b.Navigation("ParentLot"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotStatusHistory", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Lot"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.MaintenancePlan", "MaintenancePlan") + .WithMany() + .HasForeignKey("MaintenancePlanId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.MaintenanceProcedure", "Procedure") + .WithMany() + .HasForeignKey("ProcedureId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("CreatedBy"); + + b.Navigation("Equipment"); + + b.Navigation("MaintenancePlan"); + + b.Navigation("Procedure"); + + b.Navigation("Tool"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenancePlan", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Equipment"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceProcedure", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "TargetEquipment") + .WithMany() + .HasForeignKey("TargetEquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Tool", "TargetTool") + .WithMany() + .HasForeignKey("TargetToolId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("TargetEquipment"); + + b.Navigation("TargetTool"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.HasOne("MesApp.Core.Entities.MaintenanceOrder", null) + .WithMany("Records") + .HasForeignKey("MaintenanceOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("PerformedBy"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecordPart", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.MaintenanceRecord", null) + .WithMany("Parts") + .HasForeignKey("MaintenanceRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "OutputLot") + .WithMany() + .HasForeignKey("OutputLotId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "SourceOrder") + .WithMany() + .HasForeignKey("SourceOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("OutputLot"); + + b.Navigation("Product"); + + b.Navigation("SourceOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrderMaterial", b => + { + b.HasOne("MesApp.Core.Entities.Product", "ChildProduct") + .WithMany() + .HasForeignKey("ChildProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ManufacturingOrder") + .WithMany("Materials") + .HasForeignKey("ManufacturingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChildProduct"); + + b.Navigation("ManufacturingOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaterialConsumption", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NonconformanceReport", b => + { + b.HasOne("MesApp.Core.Entities.InspectionOrder", "InspectionOrder") + .WithMany() + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.AppUser", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ReworkOrder") + .WithMany() + .HasForeignKey("ReworkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("InspectionOrder"); + + b.Navigation("Lot"); + + b.Navigation("ReportedBy"); + + b.Navigation("ReworkOrder"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingLine", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.PickingOrder", null) + .WithMany("Lines") + .HasForeignKey("PickingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.HasOne("MesApp.Core.Entities.ShippingOrder", "ShippingOrder") + .WithMany() + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ShippingOrder"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Product", b => + { + b.HasOne("MesApp.Core.Entities.Location", "DefaultLocation") + .WithMany() + .HasForeignKey("DefaultLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("DefaultLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDataRecord", b => + { + b.HasOne("MesApp.Core.Entities.WorkOrderControlItem", "WorkOrderControlItem") + .WithMany() + .HasForeignKey("WorkOrderControlItemId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WorkOrder"); + + b.Navigation("WorkOrderControlItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDefect", b => + { + b.HasOne("MesApp.Core.Entities.DefectReason", "DefectReason") + .WithMany() + .HasForeignKey("DefectReasonId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ProductionRecord", "ProductionRecord") + .WithMany("Defects") + .HasForeignKey("ProductionRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DefectReason"); + + b.Navigation("ProductionRecord"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionPlan", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "OutputLot") + .WithMany() + .HasForeignKey("OutputLotId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Shift", "Shift") + .WithMany() + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("OutputLot"); + + b.Navigation("PerformedBy"); + + b.Navigation("Shift"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecordCorrection", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CorrectedBy") + .WithMany() + .HasForeignKey("CorrectedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.ProductionRecord", "ProductionRecord") + .WithMany() + .HasForeignKey("ProductionRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("CorrectedBy"); + + b.Navigation("ProductionRecord"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RefreshToken", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", "Checklist") + .WithMany() + .HasForeignKey("ChecklistId"); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId"); + + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.SkillMaster", "RequiredSkill") + .WithMany() + .HasForeignKey("RequiredSkillId"); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId"); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkProcedure", "WorkProcedure") + .WithMany() + .HasForeignKey("WorkProcedureId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Checklist"); + + b.Navigation("Equipment"); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("RequiredSkill"); + + b.Navigation("Tool"); + + b.Navigation("WorkCenter"); + + b.Navigation("WorkProcedure"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RoutingEquipment", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Routing", "Routing") + .WithMany("EquipmentCandidates") + .HasForeignKey("RoutingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Equipment"); + + b.Navigation("Routing"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SampleStorage", b => + { + b.HasOne("MesApp.Core.Entities.InspectionOrder", "InspectionOrder") + .WithMany() + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "StorageLocation") + .WithMany() + .HasForeignKey("StorageLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("InspectionOrder"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("StorageLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SetupRecord", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PerformedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShipmentJudgment", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "JudgedBy") + .WithMany() + .HasForeignKey("JudgedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.ShippingOrder", "ShippingOrder") + .WithMany() + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("JudgedBy"); + + b.Navigation("Lot"); + + b.Navigation("ShippingOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingLine", b => + { + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ShippingOrder", null) + .WithMany("Lines") + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.HasOne("MesApp.Core.Entities.Location", "TargetLocation") + .WithMany() + .HasForeignKey("TargetLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("TargetLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.StocktakeLine", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Stocktake", null) + .WithMany("Lines") + .HasForeignKey("StocktakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolIssue", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "IssuedTo") + .WithMany() + .HasForeignKey("IssuedToUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssuedTo"); + + b.Navigation("Tool"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolUsage", b => + { + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Tool"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TransferOrder", b => + { + b.HasOne("MesApp.Core.Entities.Location", "FromLocation") + .WithMany() + .HasForeignKey("FromLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "ToLocation") + .WithMany() + .HasForeignKey("ToLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("FromLocation"); + + b.Navigation("Lot"); + + b.Navigation("ToLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TroubleReport", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.AppUser", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Equipment"); + + b.Navigation("ReportedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.UserSkill", b => + { + b.HasOne("MesApp.Core.Entities.SkillMaster", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkCenter", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "Parent") + .WithMany() + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "AssignedEquipment") + .WithMany() + .HasForeignKey("AssignedEquipmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.AppUser", "AssignedUser") + .WithMany() + .HasForeignKey("AssignedUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ManufacturingOrder") + .WithMany("WorkOrders") + .HasForeignKey("ManufacturingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.SkillMaster", "RequiredSkill") + .WithMany() + .HasForeignKey("RequiredSkillId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Checklist", "RoutingChecklist") + .WithMany() + .HasForeignKey("RoutingChecklistId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkProcedure", "WorkProcedure") + .WithMany() + .HasForeignKey("WorkProcedureId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("AssignedEquipment"); + + b.Navigation("AssignedUser"); + + b.Navigation("ManufacturingOrder"); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("RequiredSkill"); + + b.Navigation("RoutingChecklist"); + + b.Navigation("WorkCenter"); + + b.Navigation("WorkProcedure"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderControlItem", b => + { + b.HasOne("MesApp.Core.Entities.ControlItem", "ControlItem") + .WithMany() + .HasForeignKey("ControlItemId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany("ControlItemSnapshots") + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ControlItem"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderStatusHistory", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "ChangedBy") + .WithMany() + .HasForeignKey("ChangedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChangedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkTimeRecord", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("User"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Checklist", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.Navigation("Results"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.Navigation("Parts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.Navigation("Items"); + + b.Navigation("Results"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.Navigation("Records"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.Navigation("Parts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.Navigation("Materials"); + + b.Navigation("WorkOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.Navigation("Defects"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.Navigation("EquipmentCandidates"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingOrder", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.Navigation("ControlItemSnapshots"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.cs b/src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.cs new file mode 100644 index 0000000..ed57f29 --- /dev/null +++ b/src/MesApp.Infrastructure/Migrations/20260922224608_AddBomItemRoutingSequence.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MesApp.Infrastructure.Migrations +{ + /// + public partial class AddBomItemRoutingSequence : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "RoutingSequence", + table: "ManufacturingOrderMaterials", + type: "INTEGER", + nullable: true); + + migrationBuilder.AddColumn( + name: "RoutingSequence", + table: "BomItems", + type: "INTEGER", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "RoutingSequence", + table: "ManufacturingOrderMaterials"); + + migrationBuilder.DropColumn( + name: "RoutingSequence", + table: "BomItems"); + } + } +} diff --git a/src/MesApp.Infrastructure/Migrations/MesAppDbContextModelSnapshot.cs b/src/MesApp.Infrastructure/Migrations/MesAppDbContextModelSnapshot.cs index c47826f..2b78802 100644 --- a/src/MesApp.Infrastructure/Migrations/MesAppDbContextModelSnapshot.cs +++ b/src/MesApp.Infrastructure/Migrations/MesAppDbContextModelSnapshot.cs @@ -192,6 +192,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("QuantityPer") .HasColumnType("TEXT"); + b.Property("RoutingSequence") + .HasColumnType("INTEGER"); + b.HasKey("Id"); b.HasIndex("ChildProductId"); @@ -1531,6 +1534,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("QuantityPer") .HasColumnType("TEXT"); + b.Property("RoutingSequence") + .HasColumnType("INTEGER"); + b.HasKey("Id"); b.HasIndex("ChildProductId"); diff --git a/src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.Designer.cs b/src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.Designer.cs new file mode 100644 index 0000000..75dac58 --- /dev/null +++ b/src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.Designer.cs @@ -0,0 +1,4950 @@ +// +using System; +using MesApp.Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MesApp.Migrations.PostgreSql.Migrations +{ + [DbContext(typeof(MesAppDbContext))] + [Migration("20260922224610_AddBomItemRoutingSequence")] + partial class AddBomItemRoutingSequence + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MesApp.Core.Entities.AppUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Department") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("MustChangePassword") + .HasColumnType("boolean"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("ShiftId") + .HasColumnType("integer"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("WorkCenterId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("ShiftId"); + + b.HasIndex("WorkCenterId"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Detail") + .HasColumnType("text"); + + b.Property("IpAddress") + .HasColumnType("text"); + + b.Property("RecordedOn") + .HasColumnType("date"); + + b.Property("TargetId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TargetType") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("text"); + + b.Property("UserName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RecordedOn"); + + b.HasIndex("Timestamp"); + + b.HasIndex("UserId"); + + b.HasIndex("Category", "Action"); + + b.HasIndex("TargetType", "TargetId"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.BomItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlternativeGroup") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ChildProductId") + .HasColumnType("integer"); + + b.Property("IsAlternative") + .HasColumnType("boolean"); + + b.Property("MakeOrBuy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ParentProductId") + .HasColumnType("integer"); + + b.Property("QuantityPer") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("RoutingSequence") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChildProductId"); + + b.HasIndex("ParentProductId", "ChildProductId") + .IsUnique(); + + b.ToTable("BomItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Checklist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Checklists"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChecklistId") + .HasColumnType("integer"); + + b.Property("IsRequired") + .HasColumnType("boolean"); + + b.Property("Sequence") + .HasColumnType("integer"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.ToTable("ChecklistItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChecklistId") + .HasColumnType("integer"); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("PerformedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ChecklistRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistResultItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChecklistItemId") + .HasColumnType("integer"); + + b.Property("ChecklistRecordId") + .HasColumnType("integer"); + + b.Property("IsChecked") + .HasColumnType("boolean"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistItemId"); + + b.HasIndex("ChecklistRecordId"); + + b.ToTable("ChecklistResultItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ControlItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("TargetProcessId") + .HasColumnType("integer"); + + b.Property("TargetProductId") + .HasColumnType("integer"); + + b.Property("TargetValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Unit") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("TargetProcessId"); + + b.HasIndex("TargetProductId"); + + b.ToTable("ControlItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.DefectReason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("DefectReasons"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AssetNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("MaintenanceParts") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("MaintenanceThreshold") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("MaintenanceType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Site") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkCenterId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AssetNo") + .IsUnique(); + + b.HasIndex("WorkCenterId"); + + b.ToTable("Equipments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("RecordedByUserId") + .HasColumnType("text"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("StopCause") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("EquipmentLogs"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentPart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("QuantityPer") + .HasPrecision(18, 4) + .HasColumnType("numeric(18,4)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("EquipmentId", "ProductId") + .IsUnique(); + + b.ToTable("EquipmentParts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDevice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CalibratedOn") + .HasColumnType("date"); + + b.Property("CalibrationCycleDays") + .HasColumnType("integer"); + + b.Property("CalibrationDueOn") + .HasColumnType("date"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Location") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("SerialNo") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("InspectionDevices"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDeviceCalibration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CalibratedOn") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InspectionDeviceId") + .HasColumnType("integer"); + + b.Property("NextDueOn") + .HasColumnType("date"); + + b.Property("PerformedByUserId") + .HasColumnType("text"); + + b.Property("Result") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("InspectionDeviceId", "CalibratedOn"); + + b.ToTable("InspectionDeviceCalibrations"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Method") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("SamplingCount") + .HasColumnType("integer"); + + b.Property("StandardValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("TargetProcessId") + .HasColumnType("integer"); + + b.Property("TargetProductId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("TargetProcessId"); + + b.HasIndex("TargetProductId"); + + b.ToTable("InspectionItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ApprovedByUserId") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("JudgedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("JudgedByUserId") + .HasColumnType("text"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OverallJudgment") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("RequestedByUserId") + .HasColumnType("text"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("TargetLotId") + .HasColumnType("integer"); + + b.Property("TargetWorkOrderId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("RequestedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("TargetLotId"); + + b.HasIndex("TargetWorkOrderId"); + + b.ToTable("InspectionOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrderItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("InspectionItemId") + .HasColumnType("integer"); + + b.Property("InspectionOrderId") + .HasColumnType("integer"); + + b.Property("ItemCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ItemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ItemVersion") + .HasColumnType("integer"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Method") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("SamplingCount") + .HasColumnType("integer"); + + b.Property("StandardValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("InspectionItemId"); + + b.HasIndex("InspectionOrderId", "InspectionItemId") + .IsUnique(); + + b.ToTable("InspectionOrderItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CorrectionNote") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("InspectedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InspectedByUserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("InspectionDeviceId") + .HasColumnType("integer"); + + b.Property("InspectionItemId") + .HasColumnType("integer"); + + b.Property("InspectionOrderId") + .HasColumnType("integer"); + + b.Property("Judgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("MeasuredValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("SampleNo") + .HasColumnType("integer"); + + b.Property("TextValue") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("InspectedByUserId"); + + b.HasIndex("InspectionDeviceId"); + + b.HasIndex("InspectionItemId"); + + b.HasIndex("InspectionOrderId"); + + b.ToTable("InspectionResults"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResultCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AfterJudgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("AfterMeasuredValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("AfterTextValue") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("BeforeJudgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("BeforeMeasuredValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("BeforeTextValue") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("CorrectedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CorrectedByUserId") + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.Property("InspectionOrderId") + .HasColumnType("integer"); + + b.Property("InspectionResultId") + .HasColumnType("integer"); + + b.Property("Reason") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("CorrectedByUserId"); + + b.HasIndex("InspectionResultId"); + + b.HasIndex("InspectionOrderId", "Id"); + + b.ToTable("InspectionResultCorrections"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryStock", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("LocationId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId", "LocationId") + .IsUnique(); + + b.HasIndex("ProductId", "LocationId"); + + b.ToTable("InventoryStocks"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("FromLocationId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PerformedByUserId") + .HasColumnType("text"); + + b.Property("PickingOrderId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ShippingOrderId") + .HasColumnType("integer"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.Property("ToLocationId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("FromLocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("Timestamp"); + + b.HasIndex("ToLocationId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("InventoryTransactions"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AreaType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("ShelfNo") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("WorkCenterId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("WorkCenterId"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Lot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresOn") + .HasColumnType("date"); + + b.Property("Grade") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("InitialQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("LotNumber") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("character varying(60)"); + + b.Property("ManufacturedOn") + .HasColumnType("date"); + + b.Property("OriginType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ParentLotId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("SourceWorkOrderId") + .HasColumnType("integer"); + + b.Property("StockStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("LotNumber") + .IsUnique(); + + b.HasIndex("ParentLotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SourceWorkOrderId"); + + b.ToTable("Lots"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotGenealogy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChildLotId") + .HasColumnType("integer"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ParentLotId") + .HasColumnType("integer"); + + b.Property("PerformedByUserId") + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("RelationType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("ChildLotId"); + + b.HasIndex("ParentLotId"); + + b.ToTable("LotGenealogies"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotStatusHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ChangedByUserId") + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.Property("FromStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("InspectionOrderId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("NonconformanceReportId") + .HasColumnType("integer"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ToStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("LotId", "Id"); + + b.ToTable("LotStatusHistories"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("text"); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("MaintenancePlanId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ProcedureId") + .HasColumnType("integer"); + + b.Property("RequestType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ScheduledDate") + .HasColumnType("date"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ToolId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByUserId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("MaintenancePlanId"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("ProcedureId"); + + b.HasIndex("Status"); + + b.HasIndex("ToolId"); + + b.ToTable("MaintenanceOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenancePlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("text"); + + b.Property("CycleDays") + .HasColumnType("integer"); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("PlanYear") + .HasColumnType("integer"); + + b.Property("ScheduledDate") + .HasColumnType("date"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId", "PlanYear"); + + b.ToTable("MaintenancePlans"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceProcedure", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("ProcedureNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Steps") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("TargetEquipmentId") + .HasColumnType("integer"); + + b.Property("TargetToolId") + .HasColumnType("integer"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProcedureNo") + .IsUnique(); + + b.HasIndex("TargetEquipmentId"); + + b.HasIndex("TargetToolId"); + + b.ToTable("MaintenanceProcedures"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MaintenanceOrderId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("PartsUsed") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Result") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("MaintenanceOrderId"); + + b.HasIndex("PerformedByUserId"); + + b.ToTable("MaintenanceRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecordPart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LocationId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("MaintenanceRecordId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 4) + .HasColumnType("numeric(18,4)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("MaintenanceRecordId"); + + b.HasIndex("ProductId"); + + b.ToTable("MaintenanceRecordParts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ApprovedByUserId") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("text"); + + b.Property("DueDate") + .HasColumnType("date"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrderType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OutputLotId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("SourceOrderId") + .HasColumnType("integer"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("OutputLotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SourceOrderId"); + + b.HasIndex("Status"); + + b.ToTable("ManufacturingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrderMaterial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlternativeGroup") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ChildProductId") + .HasColumnType("integer"); + + b.Property("IsAlternative") + .HasColumnType("boolean"); + + b.Property("ManufacturingOrderId") + .HasColumnType("integer"); + + b.Property("PlannedQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("QuantityPer") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("RoutingSequence") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChildProductId"); + + b.HasIndex("ManufacturingOrderId", "ChildProductId") + .IsUnique(); + + b.ToTable("ManufacturingOrderMaterials"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaterialConsumption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConsumedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsSubstitute") + .HasColumnType("boolean"); + + b.Property("LocationId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("Method") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("RecordedByUserId") + .HasColumnType("text"); + + b.Property("SubstituteReason") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("MaterialConsumptions"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NonconformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ActionCompletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ActionCompletedByUserId") + .HasColumnType("text"); + + b.Property("ActionInstructedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ActionInstructedByUserId") + .HasColumnType("text"); + + b.Property("ActionInstruction") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("ActionRecord") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ApprovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ApprovedByUserId") + .HasColumnType("text"); + + b.Property("CauseCategory") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CauseDetail") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InspectionOrderId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("ReportNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ReportedByUserId") + .HasColumnType("text"); + + b.Property("ReworkOrderId") + .HasColumnType("integer"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("InspectionOrderId"); + + b.HasIndex("LotId"); + + b.HasIndex("ReportNo") + .IsUnique(); + + b.HasIndex("ReportedByUserId"); + + b.HasIndex("ReworkOrderId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("NonconformanceReports"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NumberSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LastValue") + .HasColumnType("integer"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("character varying(60)"); + + b.HasKey("Id"); + + b.HasIndex("Prefix") + .IsUnique(); + + b.ToTable("NumberSequences"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LocationId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("PickingOrderId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("PickingOrderId"); + + b.HasIndex("ProductId"); + + b.ToTable("PickingLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("text"); + + b.Property("ExecutedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExecutedByUserId") + .HasColumnType("text"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ShippingOrderId") + .HasColumnType("integer"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("ShippingOrderId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("PickingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProcessMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Processes", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefaultLocationId") + .HasColumnType("integer"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Specification") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("StandardDefectRate") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Unit") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("DefaultLocationId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDataRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IsDeviation") + .HasColumnType("boolean"); + + b.Property("Item") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("NumericValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("RecordedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordedByUserId") + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("WorkOrderControlItemId") + .HasColumnType("integer"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WorkOrderControlItemId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ProductionDataRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDefect", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DefectReasonId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ProductionRecordId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("DefectReasonId"); + + b.HasIndex("ProductionRecordId"); + + b.ToTable("ProductionDefects"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BusinessDate") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PlannedQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ProcessId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("WorkCenterId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProcessId"); + + b.HasIndex("ProductId"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("BusinessDate", "ProductId", "ProcessId", "WorkCenterId") + .IsUnique(); + + b.ToTable("ProductionPlans"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ApprovedByUserId") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DefectQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("GoodQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("OutputLocationId") + .HasColumnType("integer"); + + b.Property("OutputLotId") + .HasColumnType("integer"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReworkQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ScrapQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ShiftId") + .HasColumnType("integer"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OutputLotId"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("ShiftId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ProductionRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecordCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AfterDefectQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("AfterGoodQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("AfterReworkQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("AfterScrapQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("BeforeDefectQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("BeforeGoodQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("BeforeReworkQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("BeforeScrapQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("CorrectedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CorrectedByUserId") + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.Property("ProductionRecordId") + .HasColumnType("integer"); + + b.Property("Reason") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CorrectedByUserId"); + + b.HasIndex("ProductionRecordId"); + + b.HasIndex("WorkOrderId", "Id"); + + b.ToTable("ProductionRecordCorrections"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RevokedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TokenHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TokenHash") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChecklistId") + .HasColumnType("integer"); + + b.Property("ControlItems") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("ProcessId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("RequiredSkillId") + .HasColumnType("integer"); + + b.Property("Sequence") + .HasColumnType("integer"); + + b.Property("StandardSetupMinutes") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("StandardWorkMinutes") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ToolId") + .HasColumnType("integer"); + + b.Property("WorkCenterId") + .HasColumnType("integer"); + + b.Property("WorkProcedureId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("ProcessId"); + + b.HasIndex("RequiredSkillId"); + + b.HasIndex("ToolId"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("WorkProcedureId"); + + b.HasIndex("ProductId", "Sequence") + .IsUnique(); + + b.ToTable("Routings"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RoutingEquipment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("RoutingId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("RoutingId", "EquipmentId") + .IsUnique(); + + b.ToTable("RoutingEquipments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SampleStorage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClosedByUserId") + .HasColumnType("text"); + + b.Property("ClosedOn") + .HasColumnType("date"); + + b.Property("CollectedByUserId") + .HasColumnType("text"); + + b.Property("CollectedOn") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InspectionOrderId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 4) + .HasColumnType("numeric(18,4)"); + + b.Property("RetainUntil") + .HasColumnType("date"); + + b.Property("SampleNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("StorageLocationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("InspectionOrderId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SampleNo") + .IsUnique(); + + b.HasIndex("StorageLocationId"); + + b.HasIndex("Status", "RetainUntil"); + + b.ToTable("SampleStorages"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SetupRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AbnormalityNote") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("SetupRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Shift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Shifts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShipmentJudgment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ApprovedByUserId") + .HasColumnType("text"); + + b.Property("JudgedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("JudgedByUserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("JudgmentNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Result") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ShippingOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("JudgedByUserId"); + + b.HasIndex("JudgmentNo") + .IsUnique(); + + b.HasIndex("LotId"); + + b.HasIndex("ShippingOrderId"); + + b.ToTable("ShipmentJudgments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ShippedQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ShippingOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("ShippingOrderId"); + + b.ToTable("ShippingLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("text"); + + b.Property("Destination") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PlannedDate") + .HasColumnType("date"); + + b.Property("ShippedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ShippedByUserId") + .HasColumnType("text"); + + b.Property("ShippingNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("ShippingNo") + .IsUnique(); + + b.ToTable("ShippingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SkillMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RequiresExpiry") + .HasColumnType("boolean"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("text"); + + b.Property("FinalizedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FinalizedByUserId") + .HasColumnType("text"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("StocktakeNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TargetLocationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("StocktakeNo") + .IsUnique(); + + b.HasIndex("TargetLocationId"); + + b.ToTable("Stocktakes"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.StocktakeLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CountedQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("IsAdjusted") + .HasColumnType("boolean"); + + b.Property("LocationId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("StocktakeId") + .HasColumnType("integer"); + + b.Property("TheoreticalQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("StocktakeId"); + + b.ToTable("StocktakeLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Tool", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LifeResetAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LifeThresholdCount") + .HasColumnType("integer"); + + b.Property("LifeThresholdHours") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ToolType") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Tools"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolIssue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllocatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("AllocatedByUserId") + .HasColumnType("text"); + + b.Property("IssuedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IssuedToUserId") + .HasColumnType("text"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ReturnedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReturnedByUserId") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("ToolId") + .HasColumnType("integer"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IssuedToUserId"); + + b.HasIndex("WorkOrderId"); + + b.HasIndex("ToolId", "Status"); + + b.ToTable("ToolIssues"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolUsage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("RecordedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordedByUserId") + .HasColumnType("text"); + + b.Property("ToolId") + .HasColumnType("integer"); + + b.Property("UsageCount") + .HasColumnType("integer"); + + b.Property("UsageHours") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ToolId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ToolUsages"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TransferOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("text"); + + b.Property("ExecutedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExecutedByUserId") + .HasColumnType("text"); + + b.Property("FromLocationId") + .HasColumnType("integer"); + + b.Property("LotId") + .HasColumnType("integer"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ToLocationId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("FromLocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("Status"); + + b.HasIndex("ToLocationId"); + + b.ToTable("TransferOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TroubleReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EquipmentId") + .HasColumnType("integer"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReportedByUserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseHistory") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("ReportedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("TroubleReports"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.UserSkill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AcquiredOn") + .HasColumnType("date"); + + b.Property("ExpiresOn") + .HasColumnType("date"); + + b.Property("SkillId") + .HasColumnType("integer"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("UserId", "SkillId") + .IsUnique(); + + b.ToTable("UserSkills"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkCenter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Level") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.ToTable("WorkCenters"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AssignedEquipmentId") + .HasColumnType("integer"); + + b.Property("AssignedUserId") + .HasColumnType("text"); + + b.Property("ControlItems") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DispatchOrder") + .HasColumnType("integer"); + + b.Property("ManufacturingOrderId") + .HasColumnType("integer"); + + b.Property("PlannedQuantity") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("ProcessId") + .HasColumnType("integer"); + + b.Property("ProductId") + .HasColumnType("integer"); + + b.Property("RequiredSkillId") + .HasColumnType("integer"); + + b.Property("RoutingChecklistId") + .HasColumnType("integer"); + + b.Property("RoutingSequence") + .HasColumnType("integer"); + + b.Property("StandardSetupMinutes") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("StandardWorkMinutes") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkCenterId") + .HasColumnType("integer"); + + b.Property("WorkOrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("WorkProcedureId") + .HasColumnType("integer"); + + b.Property("WorkProcedureVersion") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AssignedEquipmentId"); + + b.HasIndex("AssignedUserId"); + + b.HasIndex("ManufacturingOrderId"); + + b.HasIndex("ProcessId"); + + b.HasIndex("ProductId"); + + b.HasIndex("RequiredSkillId"); + + b.HasIndex("RoutingChecklistId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("WorkOrderNo") + .IsUnique(); + + b.HasIndex("WorkProcedureId"); + + b.ToTable("WorkOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderControlItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ControlItemId") + .HasColumnType("integer"); + + b.Property("ItemCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ItemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ItemVersion") + .HasColumnType("integer"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("TargetValue") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("Unit") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ControlItemId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("WorkOrderControlItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderStatusHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ChangedByUserId") + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.Property("FromStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ToStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChangedByUserId"); + + b.HasIndex("WorkOrderId", "Id"); + + b.ToTable("WorkOrderStatusHistories"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkProcedure", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("ProcedureNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Reference") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Steps") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ProcedureNo") + .IsUnique(); + + b.ToTable("WorkProcedures"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkTimeRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IndirectCategory") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorkOrderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WorkOrderId"); + + b.HasIndex("UserId", "StartedAt"); + + b.ToTable("WorkTimeRecords"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.AppUser", b => + { + b.HasOne("MesApp.Core.Entities.Shift", "Shift") + .WithMany() + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Shift"); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.BomItem", b => + { + b.HasOne("MesApp.Core.Entities.Product", "ChildProduct") + .WithMany() + .HasForeignKey("ChildProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "ParentProduct") + .WithMany() + .HasForeignKey("ParentProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChildProduct"); + + b.Navigation("ParentProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistItem", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", null) + .WithMany("Items") + .HasForeignKey("ChecklistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", "Checklist") + .WithMany() + .HasForeignKey("ChecklistId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Checklist"); + + b.Navigation("Equipment"); + + b.Navigation("PerformedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistResultItem", b => + { + b.HasOne("MesApp.Core.Entities.ChecklistItem", "ChecklistItem") + .WithMany() + .HasForeignKey("ChecklistItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ChecklistRecord", null) + .WithMany("Results") + .HasForeignKey("ChecklistRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChecklistItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ControlItem", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "TargetProcess") + .WithMany() + .HasForeignKey("TargetProcessId"); + + b.HasOne("MesApp.Core.Entities.Product", "TargetProduct") + .WithMany() + .HasForeignKey("TargetProductId"); + + b.Navigation("TargetProcess"); + + b.Navigation("TargetProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentLog", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Equipment"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentPart", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany("Parts") + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Equipment"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDeviceCalibration", b => + { + b.HasOne("MesApp.Core.Entities.InspectionDevice", "InspectionDevice") + .WithMany() + .HasForeignKey("InspectionDeviceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("InspectionDevice"); + + b.Navigation("PerformedBy"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionItem", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "TargetProcess") + .WithMany() + .HasForeignKey("TargetProcessId"); + + b.HasOne("MesApp.Core.Entities.Product", "TargetProduct") + .WithMany() + .HasForeignKey("TargetProductId"); + + b.Navigation("TargetProcess"); + + b.Navigation("TargetProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "RequestedBy") + .WithMany() + .HasForeignKey("RequestedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Lot", "TargetLot") + .WithMany() + .HasForeignKey("TargetLotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "TargetWorkOrder") + .WithMany() + .HasForeignKey("TargetWorkOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("RequestedBy"); + + b.Navigation("TargetLot"); + + b.Navigation("TargetWorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrderItem", b => + { + b.HasOne("MesApp.Core.Entities.InspectionItem", "InspectionItem") + .WithMany() + .HasForeignKey("InspectionItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionOrder", null) + .WithMany("Items") + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InspectionItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResult", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "InspectedBy") + .WithMany() + .HasForeignKey("InspectedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionDevice", "InspectionDevice") + .WithMany() + .HasForeignKey("InspectionDeviceId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.InspectionItem", "InspectionItem") + .WithMany() + .HasForeignKey("InspectionItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionOrder", null) + .WithMany("Results") + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InspectedBy"); + + b.Navigation("InspectionDevice"); + + b.Navigation("InspectionItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResultCorrection", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CorrectedBy") + .WithMany() + .HasForeignKey("CorrectedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.InspectionResult", "InspectionResult") + .WithMany() + .HasForeignKey("InspectionResultId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CorrectedBy"); + + b.Navigation("InspectionResult"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryStock", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryTransaction", b => + { + b.HasOne("MesApp.Core.Entities.Location", "FromLocation") + .WithMany() + .HasForeignKey("FromLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "ToLocation") + .WithMany() + .HasForeignKey("ToLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("FromLocation"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("ToLocation"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Location", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Lot", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "ParentLot") + .WithMany() + .HasForeignKey("ParentLotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "SourceWorkOrder") + .WithMany() + .HasForeignKey("SourceWorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ParentLot"); + + b.Navigation("Product"); + + b.Navigation("SourceWorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotGenealogy", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "ChildLot") + .WithMany() + .HasForeignKey("ChildLotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "ParentLot") + .WithMany() + .HasForeignKey("ParentLotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ChildLot"); + + b.Navigation("ParentLot"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotStatusHistory", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Lot"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.MaintenancePlan", "MaintenancePlan") + .WithMany() + .HasForeignKey("MaintenancePlanId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.MaintenanceProcedure", "Procedure") + .WithMany() + .HasForeignKey("ProcedureId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("CreatedBy"); + + b.Navigation("Equipment"); + + b.Navigation("MaintenancePlan"); + + b.Navigation("Procedure"); + + b.Navigation("Tool"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenancePlan", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Equipment"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceProcedure", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "TargetEquipment") + .WithMany() + .HasForeignKey("TargetEquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Tool", "TargetTool") + .WithMany() + .HasForeignKey("TargetToolId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("TargetEquipment"); + + b.Navigation("TargetTool"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.HasOne("MesApp.Core.Entities.MaintenanceOrder", null) + .WithMany("Records") + .HasForeignKey("MaintenanceOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("PerformedBy"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecordPart", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.MaintenanceRecord", null) + .WithMany("Parts") + .HasForeignKey("MaintenanceRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "OutputLot") + .WithMany() + .HasForeignKey("OutputLotId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "SourceOrder") + .WithMany() + .HasForeignKey("SourceOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("OutputLot"); + + b.Navigation("Product"); + + b.Navigation("SourceOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrderMaterial", b => + { + b.HasOne("MesApp.Core.Entities.Product", "ChildProduct") + .WithMany() + .HasForeignKey("ChildProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ManufacturingOrder") + .WithMany("Materials") + .HasForeignKey("ManufacturingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChildProduct"); + + b.Navigation("ManufacturingOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaterialConsumption", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NonconformanceReport", b => + { + b.HasOne("MesApp.Core.Entities.InspectionOrder", "InspectionOrder") + .WithMany() + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.AppUser", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ReworkOrder") + .WithMany() + .HasForeignKey("ReworkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("InspectionOrder"); + + b.Navigation("Lot"); + + b.Navigation("ReportedBy"); + + b.Navigation("ReworkOrder"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingLine", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.PickingOrder", null) + .WithMany("Lines") + .HasForeignKey("PickingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.HasOne("MesApp.Core.Entities.ShippingOrder", "ShippingOrder") + .WithMany() + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ShippingOrder"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Product", b => + { + b.HasOne("MesApp.Core.Entities.Location", "DefaultLocation") + .WithMany() + .HasForeignKey("DefaultLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("DefaultLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDataRecord", b => + { + b.HasOne("MesApp.Core.Entities.WorkOrderControlItem", "WorkOrderControlItem") + .WithMany() + .HasForeignKey("WorkOrderControlItemId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WorkOrder"); + + b.Navigation("WorkOrderControlItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDefect", b => + { + b.HasOne("MesApp.Core.Entities.DefectReason", "DefectReason") + .WithMany() + .HasForeignKey("DefectReasonId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ProductionRecord", "ProductionRecord") + .WithMany("Defects") + .HasForeignKey("ProductionRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DefectReason"); + + b.Navigation("ProductionRecord"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionPlan", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "OutputLot") + .WithMany() + .HasForeignKey("OutputLotId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Shift", "Shift") + .WithMany() + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("OutputLot"); + + b.Navigation("PerformedBy"); + + b.Navigation("Shift"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecordCorrection", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CorrectedBy") + .WithMany() + .HasForeignKey("CorrectedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.ProductionRecord", "ProductionRecord") + .WithMany() + .HasForeignKey("ProductionRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("CorrectedBy"); + + b.Navigation("ProductionRecord"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RefreshToken", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", "Checklist") + .WithMany() + .HasForeignKey("ChecklistId"); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId"); + + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.SkillMaster", "RequiredSkill") + .WithMany() + .HasForeignKey("RequiredSkillId"); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId"); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkProcedure", "WorkProcedure") + .WithMany() + .HasForeignKey("WorkProcedureId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Checklist"); + + b.Navigation("Equipment"); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("RequiredSkill"); + + b.Navigation("Tool"); + + b.Navigation("WorkCenter"); + + b.Navigation("WorkProcedure"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RoutingEquipment", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Routing", "Routing") + .WithMany("EquipmentCandidates") + .HasForeignKey("RoutingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Equipment"); + + b.Navigation("Routing"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SampleStorage", b => + { + b.HasOne("MesApp.Core.Entities.InspectionOrder", "InspectionOrder") + .WithMany() + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "StorageLocation") + .WithMany() + .HasForeignKey("StorageLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("InspectionOrder"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("StorageLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SetupRecord", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PerformedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShipmentJudgment", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "JudgedBy") + .WithMany() + .HasForeignKey("JudgedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.ShippingOrder", "ShippingOrder") + .WithMany() + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("JudgedBy"); + + b.Navigation("Lot"); + + b.Navigation("ShippingOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingLine", b => + { + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ShippingOrder", null) + .WithMany("Lines") + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.HasOne("MesApp.Core.Entities.Location", "TargetLocation") + .WithMany() + .HasForeignKey("TargetLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("TargetLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.StocktakeLine", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Stocktake", null) + .WithMany("Lines") + .HasForeignKey("StocktakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolIssue", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "IssuedTo") + .WithMany() + .HasForeignKey("IssuedToUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssuedTo"); + + b.Navigation("Tool"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolUsage", b => + { + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Tool"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TransferOrder", b => + { + b.HasOne("MesApp.Core.Entities.Location", "FromLocation") + .WithMany() + .HasForeignKey("FromLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "ToLocation") + .WithMany() + .HasForeignKey("ToLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("FromLocation"); + + b.Navigation("Lot"); + + b.Navigation("ToLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TroubleReport", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.AppUser", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Equipment"); + + b.Navigation("ReportedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.UserSkill", b => + { + b.HasOne("MesApp.Core.Entities.SkillMaster", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkCenter", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "Parent") + .WithMany() + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "AssignedEquipment") + .WithMany() + .HasForeignKey("AssignedEquipmentId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.AppUser", "AssignedUser") + .WithMany() + .HasForeignKey("AssignedUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ManufacturingOrder") + .WithMany("WorkOrders") + .HasForeignKey("ManufacturingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.SkillMaster", "RequiredSkill") + .WithMany() + .HasForeignKey("RequiredSkillId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Checklist", "RoutingChecklist") + .WithMany() + .HasForeignKey("RoutingChecklistId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkProcedure", "WorkProcedure") + .WithMany() + .HasForeignKey("WorkProcedureId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("AssignedEquipment"); + + b.Navigation("AssignedUser"); + + b.Navigation("ManufacturingOrder"); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("RequiredSkill"); + + b.Navigation("RoutingChecklist"); + + b.Navigation("WorkCenter"); + + b.Navigation("WorkProcedure"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderControlItem", b => + { + b.HasOne("MesApp.Core.Entities.ControlItem", "ControlItem") + .WithMany() + .HasForeignKey("ControlItemId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany("ControlItemSnapshots") + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ControlItem"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderStatusHistory", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "ChangedBy") + .WithMany() + .HasForeignKey("ChangedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChangedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkTimeRecord", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("User"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Checklist", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.Navigation("Results"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.Navigation("Parts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.Navigation("Items"); + + b.Navigation("Results"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.Navigation("Records"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.Navigation("Parts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.Navigation("Materials"); + + b.Navigation("WorkOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.Navigation("Defects"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.Navigation("EquipmentCandidates"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingOrder", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.Navigation("ControlItemSnapshots"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.cs b/src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.cs new file mode 100644 index 0000000..56c6847 --- /dev/null +++ b/src/MesApp.Migrations.PostgreSql/Migrations/20260922224610_AddBomItemRoutingSequence.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MesApp.Migrations.PostgreSql.Migrations +{ + /// + public partial class AddBomItemRoutingSequence : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "RoutingSequence", + table: "ManufacturingOrderMaterials", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "RoutingSequence", + table: "BomItems", + type: "integer", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "RoutingSequence", + table: "ManufacturingOrderMaterials"); + + migrationBuilder.DropColumn( + name: "RoutingSequence", + table: "BomItems"); + } + } +} diff --git a/src/MesApp.Migrations.PostgreSql/Migrations/MesAppDbContextModelSnapshot.cs b/src/MesApp.Migrations.PostgreSql/Migrations/MesAppDbContextModelSnapshot.cs index 3bc815a..6d6b506 100644 --- a/src/MesApp.Migrations.PostgreSql/Migrations/MesAppDbContextModelSnapshot.cs +++ b/src/MesApp.Migrations.PostgreSql/Migrations/MesAppDbContextModelSnapshot.cs @@ -202,6 +202,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasPrecision(18, 6) .HasColumnType("numeric(18,6)"); + b.Property("RoutingSequence") + .HasColumnType("integer"); + b.HasKey("Id"); b.HasIndex("ChildProductId"); @@ -1619,6 +1622,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasPrecision(18, 6) .HasColumnType("numeric(18,6)"); + b.Property("RoutingSequence") + .HasColumnType("integer"); + b.HasKey("Id"); b.HasIndex("ChildProductId"); diff --git a/src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.Designer.cs b/src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.Designer.cs new file mode 100644 index 0000000..4d32381 --- /dev/null +++ b/src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.Designer.cs @@ -0,0 +1,4929 @@ +// +using System; +using MesApp.Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace MesApp.Migrations.SqlServer.Migrations +{ + [DbContext(typeof(MesAppDbContext))] + [Migration("20260922224613_AddBomItemRoutingSequence")] + partial class AddBomItemRoutingSequence + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("MesApp.Core.Entities.AppUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("Department") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("MustChangePassword") + .HasColumnType("bit"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("ShiftId") + .HasColumnType("int"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("WorkCenterId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.HasIndex("ShiftId"); + + b.HasIndex("WorkCenterId"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Detail") + .HasColumnType("nvarchar(max)"); + + b.Property("IpAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("RecordedOn") + .HasColumnType("date"); + + b.Property("TargetId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("TargetType") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("UserName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("RecordedOn"); + + b.HasIndex("Timestamp"); + + b.HasIndex("UserId"); + + b.HasIndex("Category", "Action"); + + b.HasIndex("TargetType", "TargetId"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.BomItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AlternativeGroup") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ChildProductId") + .HasColumnType("int"); + + b.Property("IsAlternative") + .HasColumnType("bit"); + + b.Property("MakeOrBuy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ParentProductId") + .HasColumnType("int"); + + b.Property("QuantityPer") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("RoutingSequence") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ChildProductId"); + + b.HasIndex("ParentProductId", "ChildProductId") + .IsUnique(); + + b.ToTable("BomItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Checklist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Checklists"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChecklistId") + .HasColumnType("int"); + + b.Property("IsRequired") + .HasColumnType("bit"); + + b.Property("Sequence") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.ToTable("ChecklistItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChecklistId") + .HasColumnType("int"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("PerformedAt") + .HasColumnType("datetimeoffset"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ChecklistRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistResultItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChecklistItemId") + .HasColumnType("int"); + + b.Property("ChecklistRecordId") + .HasColumnType("int"); + + b.Property("IsChecked") + .HasColumnType("bit"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistItemId"); + + b.HasIndex("ChecklistRecordId"); + + b.ToTable("ChecklistResultItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ControlItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("TargetProcessId") + .HasColumnType("int"); + + b.Property("TargetProductId") + .HasColumnType("int"); + + b.Property("TargetValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Unit") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("TargetProcessId"); + + b.HasIndex("TargetProductId"); + + b.ToTable("ControlItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.DefectReason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("DefectReasons"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AssetNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("MaintenanceParts") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("MaintenanceThreshold") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("MaintenanceType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Site") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkCenterId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AssetNo") + .IsUnique(); + + b.HasIndex("WorkCenterId"); + + b.ToTable("Equipments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("EndedAt") + .HasColumnType("datetimeoffset"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("RecordedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("StartedAt") + .HasColumnType("datetimeoffset"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("StopCause") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("EquipmentLogs"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentPart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("QuantityPer") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("EquipmentId", "ProductId") + .IsUnique(); + + b.ToTable("EquipmentParts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDevice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CalibratedOn") + .HasColumnType("date"); + + b.Property("CalibrationCycleDays") + .HasColumnType("int"); + + b.Property("CalibrationDueOn") + .HasColumnType("date"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Location") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("SerialNo") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("InspectionDevices"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDeviceCalibration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CalibratedOn") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("InspectionDeviceId") + .HasColumnType("int"); + + b.Property("NextDueOn") + .HasColumnType("date"); + + b.Property("PerformedByUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("Result") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("InspectionDeviceId", "CalibratedOn"); + + b.ToTable("InspectionDeviceCalibrations"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Method") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("SamplingCount") + .HasColumnType("int"); + + b.Property("StandardValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("TargetProcessId") + .HasColumnType("int"); + + b.Property("TargetProductId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("TargetProcessId"); + + b.HasIndex("TargetProductId"); + + b.ToTable("InspectionItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ApprovedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("JudgedAt") + .HasColumnType("datetimeoffset"); + + b.Property("JudgedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("OverallJudgment") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("RequestedByUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("TargetLotId") + .HasColumnType("int"); + + b.Property("TargetWorkOrderId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("RequestedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("TargetLotId"); + + b.HasIndex("TargetWorkOrderId"); + + b.ToTable("InspectionOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrderItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("InspectionItemId") + .HasColumnType("int"); + + b.Property("InspectionOrderId") + .HasColumnType("int"); + + b.Property("ItemCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ItemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ItemVersion") + .HasColumnType("int"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Method") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("SamplingCount") + .HasColumnType("int"); + + b.Property("StandardValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("InspectionItemId"); + + b.HasIndex("InspectionOrderId", "InspectionItemId") + .IsUnique(); + + b.ToTable("InspectionOrderItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CorrectionNote") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("InspectedAt") + .HasColumnType("datetimeoffset"); + + b.Property("InspectedByUserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("InspectionDeviceId") + .HasColumnType("int"); + + b.Property("InspectionItemId") + .HasColumnType("int"); + + b.Property("InspectionOrderId") + .HasColumnType("int"); + + b.Property("Judgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("MeasuredValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("SampleNo") + .HasColumnType("int"); + + b.Property("TextValue") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("InspectedByUserId"); + + b.HasIndex("InspectionDeviceId"); + + b.HasIndex("InspectionItemId"); + + b.HasIndex("InspectionOrderId"); + + b.ToTable("InspectionResults"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResultCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AfterJudgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("AfterMeasuredValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("AfterTextValue") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("BeforeJudgment") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("BeforeMeasuredValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("BeforeTextValue") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("CorrectedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CorrectedByUserId") + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.Property("InspectionOrderId") + .HasColumnType("int"); + + b.Property("InspectionResultId") + .HasColumnType("int"); + + b.Property("Reason") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("CorrectedByUserId"); + + b.HasIndex("InspectionResultId"); + + b.HasIndex("InspectionOrderId", "Id"); + + b.ToTable("InspectionResultCorrections"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryStock", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId", "LocationId") + .IsUnique(); + + b.HasIndex("ProductId", "LocationId"); + + b.ToTable("InventoryStocks"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FromLocationId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("PerformedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("PickingOrderId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ShippingOrderId") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + + b.Property("ToLocationId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FromLocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("Timestamp"); + + b.HasIndex("ToLocationId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("InventoryTransactions"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AreaType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("ShelfNo") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("WorkCenterId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("WorkCenterId"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Lot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ExpiresOn") + .HasColumnType("date"); + + b.Property("Grade") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("InitialQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("LotNumber") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("nvarchar(60)"); + + b.Property("ManufacturedOn") + .HasColumnType("date"); + + b.Property("OriginType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ParentLotId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("SourceWorkOrderId") + .HasColumnType("int"); + + b.Property("StockStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.HasIndex("LotNumber") + .IsUnique(); + + b.HasIndex("ParentLotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SourceWorkOrderId"); + + b.ToTable("Lots"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotGenealogy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChildLotId") + .HasColumnType("int"); + + b.Property("OccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("ParentLotId") + .HasColumnType("int"); + + b.Property("PerformedByUserId") + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("RelationType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.HasIndex("ChildLotId"); + + b.HasIndex("ParentLotId"); + + b.ToTable("LotGenealogies"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotStatusHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChangedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ChangedByUserId") + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.Property("FromStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("InspectionOrderId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("NonconformanceReportId") + .HasColumnType("int"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ToStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.HasIndex("LotId", "Id"); + + b.ToTable("LotStatusHistories"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("MaintenancePlanId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ProcedureId") + .HasColumnType("int"); + + b.Property("RequestType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ScheduledDate") + .HasColumnType("date"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ToolId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByUserId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("MaintenancePlanId"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("ProcedureId"); + + b.HasIndex("Status"); + + b.HasIndex("ToolId"); + + b.ToTable("MaintenanceOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenancePlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CycleDays") + .HasColumnType("int"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("PlanYear") + .HasColumnType("int"); + + b.Property("ScheduledDate") + .HasColumnType("date"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId", "PlanYear"); + + b.ToTable("MaintenancePlans"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceProcedure", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("ProcedureNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Steps") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("TargetEquipmentId") + .HasColumnType("int"); + + b.Property("TargetToolId") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ProcedureNo") + .IsUnique(); + + b.HasIndex("TargetEquipmentId"); + + b.HasIndex("TargetToolId"); + + b.ToTable("MaintenanceProcedures"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("EndedAt") + .HasColumnType("datetimeoffset"); + + b.Property("MaintenanceOrderId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("PartsUsed") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Result") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("StartedAt") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("MaintenanceOrderId"); + + b.HasIndex("PerformedByUserId"); + + b.ToTable("MaintenanceRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecordPart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("MaintenanceRecordId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("MaintenanceRecordId"); + + b.HasIndex("ProductId"); + + b.ToTable("MaintenanceRecordParts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ApprovedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("DueDate") + .HasColumnType("date"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("OrderType") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OutputLotId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("SourceOrderId") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UpdatedAt") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("OutputLotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SourceOrderId"); + + b.HasIndex("Status"); + + b.ToTable("ManufacturingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrderMaterial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AlternativeGroup") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ChildProductId") + .HasColumnType("int"); + + b.Property("IsAlternative") + .HasColumnType("bit"); + + b.Property("ManufacturingOrderId") + .HasColumnType("int"); + + b.Property("PlannedQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("QuantityPer") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("RoutingSequence") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ChildProductId"); + + b.HasIndex("ManufacturingOrderId", "ChildProductId") + .IsUnique(); + + b.ToTable("ManufacturingOrderMaterials"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaterialConsumption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConsumedAt") + .HasColumnType("datetimeoffset"); + + b.Property("IsSubstitute") + .HasColumnType("bit"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("Method") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("RecordedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("SubstituteReason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("MaterialConsumptions"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NonconformanceReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ActionCompletedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ActionCompletedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ActionInstructedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ActionInstructedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ActionInstruction") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ActionRecord") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("ApprovedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ApprovedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CauseCategory") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("CauseDetail") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("InspectionOrderId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("ReportNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ReportedByUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("ReworkOrderId") + .HasColumnType("int"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InspectionOrderId"); + + b.HasIndex("LotId"); + + b.HasIndex("ReportNo") + .IsUnique(); + + b.HasIndex("ReportedByUserId"); + + b.HasIndex("ReworkOrderId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("NonconformanceReports"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NumberSequence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("LastValue") + .HasColumnType("int"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("nvarchar(60)"); + + b.HasKey("Id"); + + b.HasIndex("Prefix") + .IsUnique(); + + b.ToTable("NumberSequences"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("PickingOrderId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("PickingOrderId"); + + b.HasIndex("ProductId"); + + b.ToTable("PickingLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ExecutedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ExecutedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ShippingOrderId") + .HasColumnType("int"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNo") + .IsUnique(); + + b.HasIndex("ShippingOrderId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("PickingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProcessMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Processes", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("DefaultLocationId") + .HasColumnType("int"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Specification") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("StandardDefectRate") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Unit") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("UpdatedAt") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("DefaultLocationId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDataRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("IsDeviation") + .HasColumnType("bit"); + + b.Property("Item") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("NumericValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("RecordedAt") + .HasColumnType("datetimeoffset"); + + b.Property("RecordedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("WorkOrderControlItemId") + .HasColumnType("int"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("WorkOrderControlItemId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ProductionDataRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDefect", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DefectReasonId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ProductionRecordId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("DefectReasonId"); + + b.HasIndex("ProductionRecordId"); + + b.ToTable("ProductionDefects"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BusinessDate") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("PlannedQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("WorkCenterId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ProcessId"); + + b.HasIndex("ProductId"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("BusinessDate", "ProductId", "ProcessId", "WorkCenterId") + .IsUnique() + .HasFilter("[WorkCenterId] IS NOT NULL"); + + b.ToTable("ProductionPlans"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ApprovedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("DefectQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("EndedAt") + .HasColumnType("datetimeoffset"); + + b.Property("GoodQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("OutputLocationId") + .HasColumnType("int"); + + b.Property("OutputLotId") + .HasColumnType("int"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ReworkQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ScrapQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ShiftId") + .HasColumnType("int"); + + b.Property("StartedAt") + .HasColumnType("datetimeoffset"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OutputLotId"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("ShiftId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ProductionRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecordCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AfterDefectQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("AfterGoodQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("AfterReworkQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("AfterScrapQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("BeforeDefectQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("BeforeGoodQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("BeforeReworkQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("BeforeScrapQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("CorrectedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CorrectedByUserId") + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.Property("ProductionRecordId") + .HasColumnType("int"); + + b.Property("Reason") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CorrectedByUserId"); + + b.HasIndex("ProductionRecordId"); + + b.HasIndex("WorkOrderId", "Id"); + + b.ToTable("ProductionRecordCorrections"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ExpiresAt") + .HasColumnType("datetimeoffset"); + + b.Property("RevokedAt") + .HasColumnType("datetimeoffset"); + + b.Property("TokenHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("TokenHash") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChecklistId") + .HasColumnType("int"); + + b.Property("ControlItems") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("RequiredSkillId") + .HasColumnType("int"); + + b.Property("Sequence") + .HasColumnType("int"); + + b.Property("StandardSetupMinutes") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("StandardWorkMinutes") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ToolId") + .HasColumnType("int"); + + b.Property("WorkCenterId") + .HasColumnType("int"); + + b.Property("WorkProcedureId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ChecklistId"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("ProcessId"); + + b.HasIndex("RequiredSkillId"); + + b.HasIndex("ToolId"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("WorkProcedureId"); + + b.HasIndex("ProductId", "Sequence") + .IsUnique(); + + b.ToTable("Routings"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RoutingEquipment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("RoutingId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("RoutingId", "EquipmentId") + .IsUnique(); + + b.ToTable("RoutingEquipments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SampleStorage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClosedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ClosedOn") + .HasColumnType("date"); + + b.Property("CollectedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("CollectedOn") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("InspectionOrderId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("RetainUntil") + .HasColumnType("date"); + + b.Property("SampleNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("StorageLocationId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InspectionOrderId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("SampleNo") + .IsUnique(); + + b.HasIndex("StorageLocationId"); + + b.HasIndex("Status", "RetainUntil"); + + b.ToTable("SampleStorages"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SetupRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AbnormalityNote") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("EndedAt") + .HasColumnType("datetimeoffset"); + + b.Property("PerformedByUserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("StartedAt") + .HasColumnType("datetimeoffset"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PerformedByUserId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("SetupRecords"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Shift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("EndTime") + .HasColumnType("time"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("StartTime") + .HasColumnType("time"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Shifts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShipmentJudgment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApprovedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ApprovedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("JudgedAt") + .HasColumnType("datetimeoffset"); + + b.Property("JudgedByUserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("JudgmentNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Result") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ShippingOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("JudgedByUserId"); + + b.HasIndex("JudgmentNo") + .IsUnique(); + + b.HasIndex("LotId"); + + b.HasIndex("ShippingOrderId"); + + b.ToTable("ShipmentJudgments"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ShippedQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ShippingOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("ShippingOrderId"); + + b.ToTable("ShippingLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("Destination") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedDate") + .HasColumnType("date"); + + b.Property("ShippedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ShippedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ShippingNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.HasIndex("ShippingNo") + .IsUnique(); + + b.ToTable("ShippingOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SkillMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("RequiresExpiry") + .HasColumnType("bit"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("FinalizedAt") + .HasColumnType("datetimeoffset"); + + b.Property("FinalizedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("StocktakeNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TargetLocationId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StocktakeNo") + .IsUnique(); + + b.HasIndex("TargetLocationId"); + + b.ToTable("Stocktakes"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.StocktakeLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CountedQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("IsAdjusted") + .HasColumnType("bit"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("StocktakeId") + .HasColumnType("int"); + + b.Property("TheoreticalQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("ProductId"); + + b.HasIndex("StocktakeId"); + + b.ToTable("StocktakeLine"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Tool", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("LifeResetAt") + .HasColumnType("datetimeoffset"); + + b.Property("LifeThresholdCount") + .HasColumnType("int"); + + b.Property("LifeThresholdHours") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ToolType") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Tools"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolIssue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AllocatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("AllocatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("IssuedAt") + .HasColumnType("datetimeoffset"); + + b.Property("IssuedToUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ReturnedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ReturnedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ToolId") + .HasColumnType("int"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("IssuedToUserId"); + + b.HasIndex("WorkOrderId"); + + b.HasIndex("ToolId", "Status"); + + b.ToTable("ToolIssues"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolUsage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("RecordedAt") + .HasColumnType("datetimeoffset"); + + b.Property("RecordedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ToolId") + .HasColumnType("int"); + + b.Property("UsageCount") + .HasColumnType("int"); + + b.Property("UsageHours") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ToolId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("ToolUsages"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TransferOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("ExecutedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ExecutedByUserId") + .HasColumnType("nvarchar(max)"); + + b.Property("FromLocationId") + .HasColumnType("int"); + + b.Property("LotId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ToLocationId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FromLocationId"); + + b.HasIndex("LotId"); + + b.HasIndex("Status"); + + b.HasIndex("ToLocationId"); + + b.ToTable("TransferOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TroubleReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("EquipmentId") + .HasColumnType("int"); + + b.Property("OccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("ReportedByUserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ResponseHistory") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EquipmentId"); + + b.HasIndex("ReportedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("TroubleReports"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.UserSkill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AcquiredOn") + .HasColumnType("date"); + + b.Property("ExpiresOn") + .HasColumnType("date"); + + b.Property("SkillId") + .HasColumnType("int"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("UserId", "SkillId") + .IsUnique(); + + b.ToTable("UserSkills"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkCenter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Level") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("ParentId"); + + b.ToTable("WorkCenters"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AssignedEquipmentId") + .HasColumnType("int"); + + b.Property("AssignedUserId") + .HasColumnType("nvarchar(450)"); + + b.Property("ControlItems") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("DispatchOrder") + .HasColumnType("int"); + + b.Property("ManufacturingOrderId") + .HasColumnType("int"); + + b.Property("PlannedQuantity") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("RequiredSkillId") + .HasColumnType("int"); + + b.Property("RoutingChecklistId") + .HasColumnType("int"); + + b.Property("RoutingSequence") + .HasColumnType("int"); + + b.Property("StandardSetupMinutes") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("StandardWorkMinutes") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkCenterId") + .HasColumnType("int"); + + b.Property("WorkOrderNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("WorkProcedureId") + .HasColumnType("int"); + + b.Property("WorkProcedureVersion") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AssignedEquipmentId"); + + b.HasIndex("AssignedUserId"); + + b.HasIndex("ManufacturingOrderId"); + + b.HasIndex("ProcessId"); + + b.HasIndex("ProductId"); + + b.HasIndex("RequiredSkillId"); + + b.HasIndex("RoutingChecklistId"); + + b.HasIndex("Status"); + + b.HasIndex("WorkCenterId"); + + b.HasIndex("WorkOrderNo") + .IsUnique(); + + b.HasIndex("WorkProcedureId"); + + b.ToTable("WorkOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderControlItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ControlItemId") + .HasColumnType("int"); + + b.Property("ItemCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ItemName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ItemVersion") + .HasColumnType("int"); + + b.Property("LowerLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("TargetValue") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("Unit") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UpperLimit") + .HasPrecision(18, 6) + .HasColumnType("decimal(18,6)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ControlItemId"); + + b.HasIndex("WorkOrderId"); + + b.ToTable("WorkOrderControlItems"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderStatusHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChangedAt") + .HasColumnType("datetimeoffset"); + + b.Property("ChangedByUserId") + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.Property("FromStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ToStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ChangedByUserId"); + + b.HasIndex("WorkOrderId", "Id"); + + b.ToTable("WorkOrderStatusHistories"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkProcedure", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("ProcedureNo") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Reference") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Steps") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ProcedureNo") + .IsUnique(); + + b.ToTable("WorkProcedures"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkTimeRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EndedAt") + .HasColumnType("datetimeoffset"); + + b.Property("IndirectCategory") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("StartedAt") + .HasColumnType("datetimeoffset"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("WorkOrderId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("WorkOrderId"); + + b.HasIndex("UserId", "StartedAt"); + + b.ToTable("WorkTimeRecords"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("MesApp.Core.Entities.AppUser", b => + { + b.HasOne("MesApp.Core.Entities.Shift", "Shift") + .WithMany() + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Shift"); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.BomItem", b => + { + b.HasOne("MesApp.Core.Entities.Product", "ChildProduct") + .WithMany() + .HasForeignKey("ChildProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "ParentProduct") + .WithMany() + .HasForeignKey("ParentProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChildProduct"); + + b.Navigation("ParentProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistItem", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", null) + .WithMany("Items") + .HasForeignKey("ChecklistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", "Checklist") + .WithMany() + .HasForeignKey("ChecklistId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Checklist"); + + b.Navigation("Equipment"); + + b.Navigation("PerformedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistResultItem", b => + { + b.HasOne("MesApp.Core.Entities.ChecklistItem", "ChecklistItem") + .WithMany() + .HasForeignKey("ChecklistItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ChecklistRecord", null) + .WithMany("Results") + .HasForeignKey("ChecklistRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChecklistItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ControlItem", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "TargetProcess") + .WithMany() + .HasForeignKey("TargetProcessId"); + + b.HasOne("MesApp.Core.Entities.Product", "TargetProduct") + .WithMany() + .HasForeignKey("TargetProductId"); + + b.Navigation("TargetProcess"); + + b.Navigation("TargetProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentLog", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Equipment"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.EquipmentPart", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany("Parts") + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Equipment"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionDeviceCalibration", b => + { + b.HasOne("MesApp.Core.Entities.InspectionDevice", "InspectionDevice") + .WithMany() + .HasForeignKey("InspectionDeviceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("InspectionDevice"); + + b.Navigation("PerformedBy"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionItem", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "TargetProcess") + .WithMany() + .HasForeignKey("TargetProcessId"); + + b.HasOne("MesApp.Core.Entities.Product", "TargetProduct") + .WithMany() + .HasForeignKey("TargetProductId"); + + b.Navigation("TargetProcess"); + + b.Navigation("TargetProduct"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "RequestedBy") + .WithMany() + .HasForeignKey("RequestedByUserId"); + + b.HasOne("MesApp.Core.Entities.Lot", "TargetLot") + .WithMany() + .HasForeignKey("TargetLotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "TargetWorkOrder") + .WithMany() + .HasForeignKey("TargetWorkOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("RequestedBy"); + + b.Navigation("TargetLot"); + + b.Navigation("TargetWorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrderItem", b => + { + b.HasOne("MesApp.Core.Entities.InspectionItem", "InspectionItem") + .WithMany() + .HasForeignKey("InspectionItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionOrder", null) + .WithMany("Items") + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InspectionItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResult", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "InspectedBy") + .WithMany() + .HasForeignKey("InspectedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionDevice", "InspectionDevice") + .WithMany() + .HasForeignKey("InspectionDeviceId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.InspectionItem", "InspectionItem") + .WithMany() + .HasForeignKey("InspectionItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.InspectionOrder", null) + .WithMany("Results") + .HasForeignKey("InspectionOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InspectedBy"); + + b.Navigation("InspectionDevice"); + + b.Navigation("InspectionItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionResultCorrection", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CorrectedBy") + .WithMany() + .HasForeignKey("CorrectedByUserId"); + + b.HasOne("MesApp.Core.Entities.InspectionResult", "InspectionResult") + .WithMany() + .HasForeignKey("InspectionResultId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CorrectedBy"); + + b.Navigation("InspectionResult"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryStock", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InventoryTransaction", b => + { + b.HasOne("MesApp.Core.Entities.Location", "FromLocation") + .WithMany() + .HasForeignKey("FromLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "ToLocation") + .WithMany() + .HasForeignKey("ToLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId"); + + b.Navigation("FromLocation"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("ToLocation"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Location", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Lot", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "ParentLot") + .WithMany() + .HasForeignKey("ParentLotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "SourceWorkOrder") + .WithMany() + .HasForeignKey("SourceWorkOrderId"); + + b.Navigation("ParentLot"); + + b.Navigation("Product"); + + b.Navigation("SourceWorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotGenealogy", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "ChildLot") + .WithMany() + .HasForeignKey("ChildLotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "ParentLot") + .WithMany() + .HasForeignKey("ParentLotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ChildLot"); + + b.Navigation("ParentLot"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.LotStatusHistory", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Lot"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByUserId"); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.MaintenancePlan", "MaintenancePlan") + .WithMany() + .HasForeignKey("MaintenancePlanId"); + + b.HasOne("MesApp.Core.Entities.MaintenanceProcedure", "Procedure") + .WithMany() + .HasForeignKey("ProcedureId"); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("CreatedBy"); + + b.Navigation("Equipment"); + + b.Navigation("MaintenancePlan"); + + b.Navigation("Procedure"); + + b.Navigation("Tool"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenancePlan", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Equipment"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceProcedure", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "TargetEquipment") + .WithMany() + .HasForeignKey("TargetEquipmentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Tool", "TargetTool") + .WithMany() + .HasForeignKey("TargetToolId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("TargetEquipment"); + + b.Navigation("TargetTool"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.HasOne("MesApp.Core.Entities.MaintenanceOrder", null) + .WithMany("Records") + .HasForeignKey("MaintenanceOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("PerformedBy"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecordPart", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.MaintenanceRecord", null) + .WithMany("Parts") + .HasForeignKey("MaintenanceRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "OutputLot") + .WithMany() + .HasForeignKey("OutputLotId"); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "SourceOrder") + .WithMany() + .HasForeignKey("SourceOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("OutputLot"); + + b.Navigation("Product"); + + b.Navigation("SourceOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrderMaterial", b => + { + b.HasOne("MesApp.Core.Entities.Product", "ChildProduct") + .WithMany() + .HasForeignKey("ChildProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ManufacturingOrder") + .WithMany("Materials") + .HasForeignKey("ManufacturingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChildProduct"); + + b.Navigation("ManufacturingOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaterialConsumption", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.NonconformanceReport", b => + { + b.HasOne("MesApp.Core.Entities.InspectionOrder", "InspectionOrder") + .WithMany() + .HasForeignKey("InspectionOrderId"); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.AppUser", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedByUserId"); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ReworkOrder") + .WithMany() + .HasForeignKey("ReworkOrderId"); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId"); + + b.Navigation("InspectionOrder"); + + b.Navigation("Lot"); + + b.Navigation("ReportedBy"); + + b.Navigation("ReworkOrder"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingLine", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.PickingOrder", null) + .WithMany("Lines") + .HasForeignKey("PickingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.HasOne("MesApp.Core.Entities.ShippingOrder", "ShippingOrder") + .WithMany() + .HasForeignKey("ShippingOrderId"); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId"); + + b.Navigation("ShippingOrder"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Product", b => + { + b.HasOne("MesApp.Core.Entities.Location", "DefaultLocation") + .WithMany() + .HasForeignKey("DefaultLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("DefaultLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDataRecord", b => + { + b.HasOne("MesApp.Core.Entities.WorkOrderControlItem", "WorkOrderControlItem") + .WithMany() + .HasForeignKey("WorkOrderControlItemId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WorkOrder"); + + b.Navigation("WorkOrderControlItem"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionDefect", b => + { + b.HasOne("MesApp.Core.Entities.DefectReason", "DefectReason") + .WithMany() + .HasForeignKey("DefectReasonId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ProductionRecord", "ProductionRecord") + .WithMany("Defects") + .HasForeignKey("ProductionRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DefectReason"); + + b.Navigation("ProductionRecord"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionPlan", b => + { + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("WorkCenter"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.HasOne("MesApp.Core.Entities.Lot", "OutputLot") + .WithMany() + .HasForeignKey("OutputLotId"); + + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Shift", "Shift") + .WithMany() + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("OutputLot"); + + b.Navigation("PerformedBy"); + + b.Navigation("Shift"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecordCorrection", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "CorrectedBy") + .WithMany() + .HasForeignKey("CorrectedByUserId"); + + b.HasOne("MesApp.Core.Entities.ProductionRecord", "ProductionRecord") + .WithMany() + .HasForeignKey("ProductionRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("CorrectedBy"); + + b.Navigation("ProductionRecord"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RefreshToken", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.HasOne("MesApp.Core.Entities.Checklist", "Checklist") + .WithMany() + .HasForeignKey("ChecklistId"); + + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId"); + + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.SkillMaster", "RequiredSkill") + .WithMany() + .HasForeignKey("RequiredSkillId"); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId"); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkProcedure", "WorkProcedure") + .WithMany() + .HasForeignKey("WorkProcedureId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Checklist"); + + b.Navigation("Equipment"); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("RequiredSkill"); + + b.Navigation("Tool"); + + b.Navigation("WorkCenter"); + + b.Navigation("WorkProcedure"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.RoutingEquipment", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Routing", "Routing") + .WithMany("EquipmentCandidates") + .HasForeignKey("RoutingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Equipment"); + + b.Navigation("Routing"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SampleStorage", b => + { + b.HasOne("MesApp.Core.Entities.InspectionOrder", "InspectionOrder") + .WithMany() + .HasForeignKey("InspectionOrderId"); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "StorageLocation") + .WithMany() + .HasForeignKey("StorageLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("InspectionOrder"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + + b.Navigation("StorageLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.SetupRecord", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "PerformedBy") + .WithMany() + .HasForeignKey("PerformedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PerformedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShipmentJudgment", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "JudgedBy") + .WithMany() + .HasForeignKey("JudgedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.ShippingOrder", "ShippingOrder") + .WithMany() + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("JudgedBy"); + + b.Navigation("Lot"); + + b.Navigation("ShippingOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingLine", b => + { + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ShippingOrder", null) + .WithMany("Lines") + .HasForeignKey("ShippingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.HasOne("MesApp.Core.Entities.Location", "TargetLocation") + .WithMany() + .HasForeignKey("TargetLocationId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("TargetLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.StocktakeLine", b => + { + b.HasOne("MesApp.Core.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Stocktake", null) + .WithMany("Lines") + .HasForeignKey("StocktakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Lot"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolIssue", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "IssuedTo") + .WithMany() + .HasForeignKey("IssuedToUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssuedTo"); + + b.Navigation("Tool"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ToolUsage", b => + { + b.HasOne("MesApp.Core.Entities.Tool", "Tool") + .WithMany() + .HasForeignKey("ToolId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId"); + + b.Navigation("Tool"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TransferOrder", b => + { + b.HasOne("MesApp.Core.Entities.Location", "FromLocation") + .WithMany() + .HasForeignKey("FromLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Lot", "Lot") + .WithMany() + .HasForeignKey("LotId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Location", "ToLocation") + .WithMany() + .HasForeignKey("ToLocationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("FromLocation"); + + b.Navigation("Lot"); + + b.Navigation("ToLocation"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.TroubleReport", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "Equipment") + .WithMany() + .HasForeignKey("EquipmentId"); + + b.HasOne("MesApp.Core.Entities.AppUser", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId"); + + b.Navigation("Equipment"); + + b.Navigation("ReportedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.UserSkill", b => + { + b.HasOne("MesApp.Core.Entities.SkillMaster", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkCenter", b => + { + b.HasOne("MesApp.Core.Entities.WorkCenter", "Parent") + .WithMany() + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.HasOne("MesApp.Core.Entities.Equipment", "AssignedEquipment") + .WithMany() + .HasForeignKey("AssignedEquipmentId"); + + b.HasOne("MesApp.Core.Entities.AppUser", "AssignedUser") + .WithMany() + .HasForeignKey("AssignedUserId"); + + b.HasOne("MesApp.Core.Entities.ManufacturingOrder", "ManufacturingOrder") + .WithMany("WorkOrders") + .HasForeignKey("ManufacturingOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.ProcessMaster", "Process") + .WithMany() + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.SkillMaster", "RequiredSkill") + .WithMany() + .HasForeignKey("RequiredSkillId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.Checklist", "RoutingChecklist") + .WithMany() + .HasForeignKey("RoutingChecklistId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkCenter", "WorkCenter") + .WithMany() + .HasForeignKey("WorkCenterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkProcedure", "WorkProcedure") + .WithMany() + .HasForeignKey("WorkProcedureId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("AssignedEquipment"); + + b.Navigation("AssignedUser"); + + b.Navigation("ManufacturingOrder"); + + b.Navigation("Process"); + + b.Navigation("Product"); + + b.Navigation("RequiredSkill"); + + b.Navigation("RoutingChecklist"); + + b.Navigation("WorkCenter"); + + b.Navigation("WorkProcedure"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderControlItem", b => + { + b.HasOne("MesApp.Core.Entities.ControlItem", "ControlItem") + .WithMany() + .HasForeignKey("ControlItemId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany("ControlItemSnapshots") + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ControlItem"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrderStatusHistory", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "ChangedBy") + .WithMany() + .HasForeignKey("ChangedByUserId"); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChangedBy"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkTimeRecord", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.WorkOrder", "WorkOrder") + .WithMany() + .HasForeignKey("WorkOrderId"); + + b.Navigation("User"); + + b.Navigation("WorkOrder"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("MesApp.Core.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Checklist", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ChecklistRecord", b => + { + b.Navigation("Results"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Equipment", b => + { + b.Navigation("Parts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.InspectionOrder", b => + { + b.Navigation("Items"); + + b.Navigation("Results"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceOrder", b => + { + b.Navigation("Records"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.MaintenanceRecord", b => + { + b.Navigation("Parts"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ManufacturingOrder", b => + { + b.Navigation("Materials"); + + b.Navigation("WorkOrders"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.PickingOrder", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ProductionRecord", b => + { + b.Navigation("Defects"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Routing", b => + { + b.Navigation("EquipmentCandidates"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.ShippingOrder", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.Stocktake", b => + { + b.Navigation("Lines"); + }); + + modelBuilder.Entity("MesApp.Core.Entities.WorkOrder", b => + { + b.Navigation("ControlItemSnapshots"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.cs b/src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.cs new file mode 100644 index 0000000..0dd8cd4 --- /dev/null +++ b/src/MesApp.Migrations.SqlServer/Migrations/20260922224613_AddBomItemRoutingSequence.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MesApp.Migrations.SqlServer.Migrations +{ + /// + public partial class AddBomItemRoutingSequence : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "RoutingSequence", + table: "ManufacturingOrderMaterials", + type: "int", + nullable: true); + + migrationBuilder.AddColumn( + name: "RoutingSequence", + table: "BomItems", + type: "int", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "RoutingSequence", + table: "ManufacturingOrderMaterials"); + + migrationBuilder.DropColumn( + name: "RoutingSequence", + table: "BomItems"); + } + } +} diff --git a/src/MesApp.Migrations.SqlServer/Migrations/MesAppDbContextModelSnapshot.cs b/src/MesApp.Migrations.SqlServer/Migrations/MesAppDbContextModelSnapshot.cs index 1230726..d589440 100644 --- a/src/MesApp.Migrations.SqlServer/Migrations/MesAppDbContextModelSnapshot.cs +++ b/src/MesApp.Migrations.SqlServer/Migrations/MesAppDbContextModelSnapshot.cs @@ -203,6 +203,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasPrecision(18, 6) .HasColumnType("decimal(18,6)"); + b.Property("RoutingSequence") + .HasColumnType("int"); + b.HasKey("Id"); b.HasIndex("ChildProductId"); @@ -1620,6 +1623,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasPrecision(18, 6) .HasColumnType("decimal(18,6)"); + b.Property("RoutingSequence") + .HasColumnType("int"); + b.HasKey("Id"); b.HasIndex("ChildProductId"); diff --git a/tests/MesApp.Api.Tests/ExecutionTests.cs b/tests/MesApp.Api.Tests/ExecutionTests.cs index 94f65e9..7c6ad37 100644 --- a/tests/MesApp.Api.Tests/ExecutionTests.cs +++ b/tests/MesApp.Api.Tests/ExecutionTests.cs @@ -409,6 +409,58 @@ public async Task バックフラッシュでMBOM数量分の部材が自動消 Assert.Equal(20m, consumptions[0].Quantity); } + [Fact] + public async Task バックフラッシュは部材を消費工程の作業指示でだけ引く() + { + using var factory = new ApiFactory(); + using var admin = await TestAuth.CreateAdminClientAsync(factory); + var ctx = await Phase3TestData.SetupAsync(admin); + // RM-01 は工程1で消費、RM-02 は消費工程を指定しない(=最終工程の工程2) + var packing = await MasterTests.CreateProductAsync(admin, "RM-02", "梱包材", ProductType.Material); + (await admin.PutAsJsonAsync($"/api/products/{ctx.ProductId}/bom", new List + { + new(ctx.MaterialId, Phase3TestData.BomQuantityPer, MakeOrBuy.InHouse, null, RoutingSequence: 1), + new(packing.Id, 1m, MakeOrBuy.InHouse, null), + })).EnsureSuccessStatusCode(); + var materialLot = await Phase3TestData.ReceiveAsync(admin, ctx.MaterialId, 100m, ctx.MaterialLocationId); + var packingLot = await Phase3TestData.ReceiveAsync(admin, packing.Id, 100m, ctx.MaterialLocationId); + var order = await Phase3TestData.CreateReleasedOrderAsync(admin, ctx.ProductId, 10m); + + // 未指定の行は展開時に最終工程へ解決して固定する(以降の工順改訂に左右されない) + Assert.Equal(1, order.Materials!.Single(m => m.ChildProductId == ctx.MaterialId).RoutingSequence); + Assert.Equal(2, order.Materials!.Single(m => m.ChildProductId == packing.Id).RoutingSequence); + + // 工程ごとにバックフラッシュしても、各部材は自分の工程で1回だけ引かれる(工程数ぶん二重に減らない) + (await admin.PostAsJsonAsync($"/api/work-orders/{order.WorkOrders[0].Id}/production-records", + new ProductionRecordRequest(10m, 0m, DateTimeOffset.Now.AddHours(-2), DateTimeOffset.Now.AddHours(-1), + null, Backflush: true))).EnsureSuccessStatusCode(); + Assert.Equal(80m, await Phase3TestData.GetStockQuantityAsync(admin, materialLot.Id)); + Assert.Equal(100m, await Phase3TestData.GetStockQuantityAsync(admin, packingLot.Id)); + + (await admin.PostAsJsonAsync($"/api/work-orders/{order.WorkOrders[1].Id}/production-records", + new ProductionRecordRequest(10m, 0m, DateTimeOffset.Now.AddHours(-1), DateTimeOffset.Now, + ctx.ProductLocationId, Backflush: true))).EnsureSuccessStatusCode(); + Assert.Equal(80m, await Phase3TestData.GetStockQuantityAsync(admin, materialLot.Id)); + Assert.Equal(90m, await Phase3TestData.GetStockQuantityAsync(admin, packingLot.Id)); + } + + [Fact] + public async Task 消費する部材の無い工程ではバックフラッシュを拒否する() + { + using var factory = new ApiFactory(); + using var admin = await TestAuth.CreateAdminClientAsync(factory); + var ctx = await Phase3TestData.SetupAsync(admin); + var materialLot = await Phase3TestData.ReceiveAsync(admin, ctx.MaterialId, 100m, ctx.MaterialLocationId); + var order = await Phase3TestData.CreateReleasedOrderAsync(admin, ctx.ProductId, 10m); + + // 部材は消費工程が未指定=最終工程(工程2)。工程1で引こうとしたら、黙って何もしないのではなく知らせる + var record = await admin.PostAsJsonAsync($"/api/work-orders/{order.WorkOrders[0].Id}/production-records", + new ProductionRecordRequest(10m, 0m, DateTimeOffset.Now.AddHours(-1), DateTimeOffset.Now, + null, Backflush: true)); + Assert.Equal(HttpStatusCode.BadRequest, record.StatusCode); + Assert.Equal(100m, await Phase3TestData.GetStockQuantityAsync(admin, materialLot.Id)); + } + [Fact] public async Task バックフラッシュは代替部品を消費しない() { diff --git a/tests/MesApp.Api.Tests/MasterCsvTests.cs b/tests/MesApp.Api.Tests/MasterCsvTests.cs index 7c44af5..c2e05a3 100644 --- a/tests/MesApp.Api.Tests/MasterCsvTests.cs +++ b/tests/MesApp.Api.Tests/MasterCsvTests.cs @@ -206,9 +206,9 @@ public async Task MBOMと工順をコード指定のCSVで一括登録できる( """)).Succeeded); var bom = await ImportAsync(client, "bom", """ - ParentProductCode,ChildProductCode,QuantityPer,MakeOrBuy,AlternativeGroup - FG-01,RM-01,2,InHouse, - FG-01,RM-02,1.5,Outsourced,ALT-1 + ParentProductCode,ChildProductCode,QuantityPer,MakeOrBuy,AlternativeGroup,RoutingSequence + FG-01,RM-01,2,InHouse,,1 + FG-01,RM-02,1.5,Outsourced,ALT-1, """); Assert.True(bom.Succeeded, string.Join(" / ", bom.Errors.Select(e => e.Message))); Assert.Equal(1, bom.Created); @@ -218,6 +218,9 @@ public async Task MBOMと工順をコード指定のCSVで一括登録できる( var bomLines = await client.GetFromJsonAsync>($"/api/products/{parentId}/bom"); Assert.Equal(2, bomLines!.Count); Assert.Equal(1.5m, bomLines.Single(b => b.ChildProductCode == "RM-02").QuantityPer); + // 消費工程は空なら未指定(最終工程で消費) + Assert.Equal(1, bomLines.Single(b => b.ChildProductCode == "RM-01").RoutingSequence); + Assert.Null(bomLines.Single(b => b.ChildProductCode == "RM-02").RoutingSequence); var routing = await ImportAsync(client, "routing", """ ProductCode,Sequence,ProcessCode,StandardWorkMinutes,StandardSetupMinutes,ControlItems diff --git a/tests/MesApp.Api.Tests/ProductionTests.cs b/tests/MesApp.Api.Tests/ProductionTests.cs index 9f873cf..714e7ea 100644 --- a/tests/MesApp.Api.Tests/ProductionTests.cs +++ b/tests/MesApp.Api.Tests/ProductionTests.cs @@ -413,6 +413,26 @@ public async Task 工順未登録の品目の指図は展開できない() Assert.Equal(HttpStatusCode.BadRequest, expanded.StatusCode); } + [Fact] + public async Task MBOMの消費工程が工順に無い品目の指図は展開できない() + { + using var factory = new ApiFactory(); + using var admin = await TestAuth.CreateAdminClientAsync(factory); + var ctx = await Phase3TestData.SetupAsync(admin); + // 工順は工程順序 1・2。MBOMと工順は別々に改訂できるため、ずれは展開時に止める + (await admin.PutAsJsonAsync($"/api/products/{ctx.ProductId}/bom", new List + { + new(ctx.MaterialId, Phase3TestData.BomQuantityPer, MakeOrBuy.InHouse, null, RoutingSequence: 3), + })).EnsureSuccessStatusCode(); + var order = await CreateOrderAsync(admin, ctx.ProductId); + await admin.PostAsync($"/api/manufacturing-orders/{order.Id}/approve", null); + + var expanded = await admin.PostAsJsonAsync( + $"/api/manufacturing-orders/{order.Id}/expand", new ExpandRequest(null)); + Assert.Equal(HttpStatusCode.BadRequest, expanded.StatusCode); + Assert.Contains("RM-01", await expanded.Content.ReadAsStringAsync()); + } + [Fact] public async Task 承認済みの指図を変更すると未承認に戻る() { From ecdfab8439973734aff131fa5a8d71a1292cf3eb Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 07:59:57 +0900 Subject: [PATCH 02/10] =?UTF-8?q?=E4=BD=9C=E6=A5=AD=E6=8C=87=E7=A4=BA?= =?UTF-8?q?=E6=9B=B8=E3=81=AE=E9=83=A8=E6=9D=90=E3=82=92=E6=8C=87=E5=9B=B3?= =?UTF-8?q?=E3=81=AE=E4=BA=88=E5=AE=9A=E6=9D=90=E6=96=99=E3=81=8B=E3=82=89?= =?UTF-8?q?=E3=80=81=E3=81=9D=E3=81=AE=E5=B7=A5=E7=A8=8B=E3=81=A7=E4=BD=BF?= =?UTF-8?q?=E3=81=86=E3=82=82=E3=81=AE=E3=81=A0=E3=81=91=E5=87=BA=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 作業指示書が現行のMBOMを全行印刷しており、展開時に固定した予定材料(Spec.md 5.7)と 食い違い得るうえ、工程に関係なく全部材が載っていた。 - 指図の予定材料のうち、この作業指示の工程を消費工程とする行だけを出す (消費工程が空の行は最終工程で使う扱い。バックフラッシュと同じ規則) - 予定材料は内外製区分を持たないため、列を代替部品グループに替える - 利用者ガイド(実行)の指示書の説明を更新 MES.md: B-10-30-04(作業指示書) Co-Authored-By: Claude Opus 5.5 --- docs/execution.md | 2 +- .../Pages/Print/WorkInstruction.razor | 32 ++++++++++++------- src/MesApp.Client.Web/Shared/UiText.en.resx | 8 ++--- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/docs/execution.md b/docs/execution.md index 6330e19..fd582e4 100644 --- a/docs/execution.md +++ b/docs/execution.md @@ -64,7 +64,7 @@ next_title: 物流・在庫管理 - **段取り**:段取り実績とチェックリストの記録 - **実績入力**:着手・出来高報告・完了承認 -- **指示書**:作業指示書の印刷(別タブ)。構成部品(MBOM)と工程情報が印刷されます +- **指示書**:作業指示書の印刷(別タブ)。この工程で使う部材(指図を展開したときのMBOMのうち、この工程を消費工程とするもの)と工程情報が印刷されます --- diff --git a/src/MesApp.Client.Web/Pages/Print/WorkInstruction.razor b/src/MesApp.Client.Web/Pages/Print/WorkInstruction.razor index 653859e..5893503 100644 --- a/src/MesApp.Client.Web/Pages/Print/WorkInstruction.razor +++ b/src/MesApp.Client.Web/Pages/Print/WorkInstruction.razor @@ -2,7 +2,8 @@ @attribute [Authorize] @inject HttpClient Http -@* 作業指示書(B-10-30-04)。構成部品(MBOM)・工程情報を含む *@ +@* 作業指示書(B-10-30-04)。この工程で使う部材と工程情報を含む。 + 部材は現行のMBOMではなく指図の予定材料(展開時に固定。Spec.md 5.7)から、この工程を消費工程とする行だけを出す *@ @L["作業指示書 - Parallel Factory MES"] @if (_workOrder is null) @@ -36,23 +37,23 @@ else
    @L["子品目"]@L["必要数量(親1単位)"]@L["内外製"]@L["代替グループ"]@L["代替部品"]
    @L["子品目"]@L["必要数量(親1単位)"]@L["内外製"]@L["代替グループ"]@L["代替部品"]@L["消費工程"]
    @EnumLabels.Of(line.MakeOrBuy) @(line.AlternativeGroup ?? "-") @(line.IsAlternative ? L["代替"] : L["主"])@StepLabel(line.RoutingSequence)
    -

    @L["構成部品(MBOM)"]

    - @if (_bom.Count == 0) +

    @L["この工程で使う部材(予定材料)"]

    + @if (_materials.Count == 0) { -

    @L["MBOMは登録されていません。"]

    +

    @L["この工程で使う部材はありません。"]

    } else { - + - @foreach (var line in _bom) + @foreach (var line in _materials) { - - + + - + } @@ -76,15 +77,22 @@ else [Parameter] public int Id { get; set; } private WorkOrderResponse? _workOrder; - private List _bom = []; + private List _materials = []; protected override async Task OnParametersSetAsync() { _workOrder = await Http.GetFromJsonAsync($"api/work-orders/{Id}"); if (_workOrder is not null) { - _bom = await Http.GetFromJsonAsync>( - $"api/products/{_workOrder.ProductId}/bom") ?? []; + var order = await Http.GetFromJsonAsync( + $"api/manufacturing-orders/{_workOrder.ManufacturingOrderId}"); + // 消費工程が空の行は消費工程の追加前に展開した指図のもので、最終工程で使う扱い(バックフラッシュと同じ) + var finalSequence = order?.WorkOrders + .Where(w => w.Status != WorkOrderStatus.Canceled) + .Max(w => (int?)w.RoutingSequence); + var sequence = _workOrder.RoutingSequence; + _materials = [.. (order?.Materials ?? []) + .Where(m => m.RoutingSequence == sequence || (m.RoutingSequence is null && sequence == finalSequence))]; } } } diff --git a/src/MesApp.Client.Web/Shared/UiText.en.resx b/src/MesApp.Client.Web/Shared/UiText.en.resx index 1985960..54ce73d 100644 --- a/src/MesApp.Client.Web/Shared/UiText.en.resx +++ b/src/MesApp.Client.Web/Shared/UiText.en.resx @@ -2127,11 +2127,11 @@ WORK INSTRUCTION - - Components (MBOM) + + Materials used in this step (planned materials) - - No MBOM registered. + + No materials are used in this step. Required Qty (for planned qty) From c3898e92d83beb97369cf05058634cbc49a1b317 Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:07:52 +0900 Subject: [PATCH 03/10] =?UTF-8?q?=E5=93=81=E7=9B=AE=E3=81=AE=E6=A8=99?= =?UTF-8?q?=E6=BA=96=E4=B8=8D=E8=89=AF=E7=8E=87=E3=82=92=E6=8C=87=E5=9B=B3?= =?UTF-8?q?=E3=81=AE=E4=BA=88=E5=AE=9A=E6=9D=90=E6=96=99=E3=81=AB=E5=8F=8D?= =?UTF-8?q?=E6=98=A0=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 標準不良率は A-40-10-04(不良率などのMBOM付加情報)として入力できたが、どこにも使われていなかった。 - 予定数量を 原単位×指図数量÷(1-親品目の標準不良率) とする。不良品も部材を消費する (バックフラッシュは良品+不良の数で引く)ため、良品を指図数量だけ得るのに要る部材を見込む - 割り切れない値は列の精度(小数6桁)で切り上げる(切り捨てると欠品側にずれる) - ÷(1-率) のため標準不良率は 0〜99.99 とする(単票API・CSV・画面の入力) - バックフラッシュの消費量は実績(良品+不良)基準のまま - Spec.md 改訂118、利用者ガイド(マスタ)を更新 MES.md: A-40-10-04(その他MBOM関連情報) Co-Authored-By: Claude Opus 5.5 --- Spec.md | 5 ++-- docs/masters.md | 4 ++- src/MesApp.Api/Localization/ApiText.en.resx | 3 +++ .../Services/ManufacturingOrderService.cs | 13 +++++++++- src/MesApp.Api/Services/MasterCsvKinds.cs | 2 +- .../Services/MasterCsvService.Import.cs | 2 +- .../Pages/Masters/ProductsTab.razor | 2 +- .../Contracts/Masters/MasterContracts.cs | 3 ++- src/MesApp.Core/Entities/Masters.cs | 5 +++- tests/MesApp.Api.Tests/MasterCsvTests.cs | 2 +- tests/MesApp.Api.Tests/ProductionTests.cs | 25 +++++++++++++++++++ 11 files changed, 56 insertions(+), 10 deletions(-) diff --git a/Spec.md b/Spec.md index 3d02b74..6d35f31 100644 --- a/Spec.md +++ b/Spec.md @@ -116,6 +116,7 @@ 改訂115: 2026-09-23(3.8節・7.2節:生産計画をマスタの一括ZIPの取込・出力から外した(改訂113で含めていた)。生産計画はマスタではなく日々増える業務データで、全期間がZIPに入り、マスタを別環境へ移すと過去の計画まで付いていったため。取込の仕組み(キーで上書き)は引き続きマスタCSVのものを使う。計画のCSV出力は全件をやめ、一覧と同じ絞り込みの `api/production-plans/csv` を追加した。あわせて、3か月分の実績サンプルと同じ期間の生産計画のサンプル `samples/production-plans/` を追加し(`scripts/New-SampleBulkActuals.ps1` が乱数を使わず生成。実績の内容は変えない)、リリースに `samples-production-plans.csv` として添付する。利用者向けガイド(生産管理・ロールと権限など)に生産計画・予実の操作を追記) 改訂116: 2026-09-23(3.8節:実績CSVに出荷指示 `shipping-orders`・出荷判定 `shipment-judgments`・出荷実行 `shipments` を追加した。サンプルの実績で出荷だけが画面操作で、製造から出荷までをCSVだけではたどれなかった。判定と出荷で取込の権限が違うため3種別に分ける。出荷判定の登録・承認を `ShipmentJudgmentsController` から `ShipmentJudgmentService` へ移し、単票APIとCSV取込の両方から呼ぶ。出荷指示は後続のCSVから指すため出荷番号の手入力を許す(`SH〜` は自動採番用として拒否)。サンプル `samples/actual-csv/13〜15` を追加) 改訂117: 2026-09-23(3.9節・5.1節・5.2節:MBOMの行に消費工程(`BomItem.RoutingSequence`。親品目の工順の工程順序)を追加した。バックフラッシュが作業指示の工程にかかわらず指図の予定材料をすべて引いていたため、複数工程の品目で工程ごとにバックフラッシュすると部材が工程数ぶん減っていた。バックフラッシュはその作業指示の工程で消費する部材だけを引き、消費する部材の無い工程では拒否する。未指定の行は最終工程で消費し、展開時に予定材料へ最終工程の工程順序を入れて固定する。工順は一括置換で行が作り直されるためIDではなく工程順序で指し、工順に無い工程順序は展開時に拒否する。MBOMのCSVに `RoutingSequence` 列を追加し、サンプル `samples/master-csv/15_bom.csv` は実績サンプルの部材投入に合わせて工程10とした) +改訂118: 2026-09-23(5.1節・5.2節:品目の標準不良率を指図の予定材料に反映するようにした。A-40-10-04(不良率などのMBOM付加情報)として入力できたが、どこにも使われていなかった。予定数量を 原単位×指図数量÷(1-親品目の標準不良率) とする。不良品も部材を消費する(バックフラッシュは良品+不良の数で引く)ため、良品を指図数量だけ得るのに要る部材を見込む。割り切れない値は列の精度(小数6桁)で切り上げる(切り捨てると欠品側にずれる)。÷(1-率) のため標準不良率は100%を受け付けず 0〜99.99 とした(単票API・CSV)。バックフラッシュの消費量は実績(良品+不良)基準のままで変えない) 参考: みんなのMES(min-MES) https://min-mes.com/ / OSS: https://github.com/mihatama/open-mes-project --- @@ -398,7 +399,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと | Shift(勤務シフト/直) | シフトコード、名称、開始時刻、終了時刻(開始時刻以下なら翌日にまたぐ夜勤)、状態(F-10-10-01)。3.9節の製造日が夜勤を前提にしているのに対し「その実績がどの直か」を表す | | SkillMaster(スキル・資格マスタ) | コード、名称、種別(スキル/資格)、有効期限管理要否(F-20-10-01) | | UserSkill(従業員スキル・資格) | ユーザーID、スキル/資格ID、取得日、有効期限、状態(F-20-10-02〜05) | -| Product(品目マスタ) | 品目コード、品目名、単位、規格、品目区分(製品/半製品・中間品/部材)、標準不良率、**既定ロケーション**(推奨ロケーション指示の第一候補。D-10-30-03) | +| Product(品目マスタ) | 品目コード、品目名、単位、規格、品目区分(製品/半製品・中間品/部材)、標準不良率(0〜99.99%。指図の予定材料を割り増す。A-40-10-04)、**既定ロケーション**(推奨ロケーション指示の第一候補。D-10-30-03) | | BomItem(MBOM明細) | 親品目ID、子品目ID(部材)、必要数量(親1単位あたり)、内外製区分、代替部品グループ、**代替部品フラグ**(同一グループ内の主材料でない行。A-40-10)、**消費工程**(工順の工程順序。未指定なら最終工程。B-40-10-09) | | Process(工程マスタ) | 工程コード、工程名、工程区分(内製/外注) | | Routing(工順/BOP) | 品目ID、工程順序、工程ID、標準作業時間(**1個あたり**)、標準段取り時間(**1回あたり**)、必要スキルID、**候補設備**・治工具、**作業区**、工程管理項目、チェックリストID、**作業手順書ID**(A-40-20、I-30-20)
    標準時間の予実(3.2節 B-60-10-05)は 段取り時間+作業時間×数量 で予定を出す | @@ -423,7 +424,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと |---|---| | ProductionPlan(生産計画) | 製造日、品目ID、工程ID、作業区ID(任意)、計画数量(0以上)、備考。一意キーは製造日・品目・工程・作業区(作業区なしの重複はAPIで止める)。同じ製造日・品目・工程で作業区の範囲が重なる計画(作業区なしと作業区あり、上位の段と配下の段)は併存させない(予実で二重に数えるため。兄弟の作業区は可)。既存の指図・実績からは参照しない(A-30-10-01) | | ManufacturingOrder(製造指図) | 指図番号、品目ID、数量、納期、指図区分(通常/リワーク/突発)、状態(未承認/承認済/展開済/完了/取消)、承認者、元指図ID(リワーク時)(A-20、B-70-10) | -| ManufacturingOrderMaterial(指図の予定材料) | 指図ID、部材品目ID、原単位(親1単位あたり)、予定数量(=原単位×指図数量)、代替部品グループ、消費工程(未指定のMBOM行は展開時の最終工程に解決。本項目の追加前に展開した指図は空で、最終工程として扱う)。展開時にMBOMから固定し、部材投入の照合とバックフラッシュの基準にする(A-40-10、B-30-20) | +| ManufacturingOrderMaterial(指図の予定材料) | 指図ID、部材品目ID、原単位(親1単位あたり)、予定数量(=原単位×指図数量÷(1-親品目の標準不良率)。小数6桁で切り上げ)、代替部品グループ、消費工程(未指定のMBOM行は展開時の最終工程に解決。本項目の追加前に展開した指図は空で、最終工程として扱う)。展開時にMBOMから固定し、部材投入の照合とバックフラッシュの基準にする(A-40-10、B-30-20) | | WorkOrderControlItem(作業指示の工程管理項目) | 作業指示ID、工程管理項目ID、**展開時点のスナップショット**(項目コード・名称・単位・版数・指示値・許容下限/上限)。実績の逸脱判定と画面表示はこれを使い、マスタの現在値を参照しない(B-30-30-04) | | WorkOrderStatusHistory(作業指示の状態履歴) | 作業指示ID、変更前状態、変更後状態、契機(差立/着手/実績入力/承認/指図取消)、備考、変更者、変更日時。配布・着手・完了・承認・取消の遷移を業務履歴として残す(B-10、B-30-30、B-40-10-10) | | WorkOrder(作業指示) | 指示番号、製造指図ID、品目ID、工程ID、計画数、着手順、割当作業者ID、割当設備ID、**作業区(展開時の工順スナップショット)**、**作業手順書IDと展開時点の版数**、状態(未配布/配布済/着手/完了/承認済)(B-10) | diff --git a/docs/masters.md b/docs/masters.md index c252b97..1ab8f48 100644 --- a/docs/masters.md +++ b/docs/masters.md @@ -61,7 +61,7 @@ next_title: 生産管理 | 単位 | 個、kg など | | 品目区分 | 製品/半製品・中間品/部材 | | 規格 | 任意の規格情報 | -| 標準不良率(%) | 参考値として保持 | +| 標準不良率(%) | 製造指図を展開したときの予定材料をこの率ぶん割り増します(0〜99.99) | 登録済みの品目は一覧に表示され、**編集**で内容を変更、**無効化**で以後の選択肢から外せます (過去の実績は残ります)。 @@ -89,6 +89,8 @@ next_title: 生産管理 MBOMは、実績入力の**バックフラッシュ**(部材の自動消費)で使われます。 バックフラッシュを使う予定があれば必ず登録してください。 +製造指図を展開すると、MBOMから予定材料が作られます。予定数量は **必要数量 × 指図数量 ÷ (1 − 標準不良率)** です。 +不良になる分も部材を使うため、親品目の標準不良率ぶん多めに見込みます(例:必要数量2・指図数量10・標準不良率20%なら予定数量25)。 バックフラッシュは各部材を**消費工程の作業指示でだけ**引くので、組立の工程で使う部材は消費工程に組立の工程を選んでください。
    diff --git a/src/MesApp.Api/Localization/ApiText.en.resx b/src/MesApp.Api/Localization/ApiText.en.resx index ae10f3c..eb2b511 100644 --- a/src/MesApp.Api/Localization/ApiText.en.resx +++ b/src/MesApp.Api/Localization/ApiText.en.resx @@ -1995,4 +1995,7 @@ Sequence in the parent item's routing. Blank means the final step. Backflush consumes the material at this step + + 0 to 99.99. Planned materials of an order are increased by this rate + diff --git a/src/MesApp.Api/Services/ManufacturingOrderService.cs b/src/MesApp.Api/Services/ManufacturingOrderService.cs index 6493dd2..d0d07e6 100644 --- a/src/MesApp.Api/Services/ManufacturingOrderService.cs +++ b/src/MesApp.Api/Services/ManufacturingOrderService.cs @@ -313,7 +313,7 @@ .. controlItems ManufacturingOrder = order, ChildProductId = item.ChildProductId, QuantityPer = item.QuantityPer, - PlannedQuantity = item.QuantityPer * order.Quantity, + PlannedQuantity = PlannedMaterialQuantity(item.QuantityPer, order.Quantity, order.Product!.StandardDefectRate), AlternativeGroup = item.AlternativeGroup, IsAlternative = item.IsAlternative, RoutingSequence = item.RoutingSequence ?? finalSequence, @@ -334,4 +334,15 @@ await auditLogger.LogAsync("Production", "Expand", nameof(ManufacturingOrder), o }, ct: ct); return OrderOutcome.Ok(order); } + + /// + /// 予定材料の数量(A-40-10-04)。親品目の標準不良率ぶん割り増す:原単位×指図数量÷(1-率)。 + /// 不良品も部材を消費するため、良品を指図数量だけ得るには不良になる分の部材も要る。 + /// 割り切れない値は列の精度(小数6桁)で切り上げる(切り捨てると欠品側にずれる) + /// + internal static decimal PlannedMaterialQuantity(decimal quantityPer, decimal orderQuantity, decimal defectRatePercent) + { + var quantity = quantityPer * orderQuantity / (1m - defectRatePercent / 100m); + return Math.Ceiling(quantity * 1_000_000m) / 1_000_000m; + } } diff --git a/src/MesApp.Api/Services/MasterCsvKinds.cs b/src/MesApp.Api/Services/MasterCsvKinds.cs index 4cf9c6a..d1f15b6 100644 --- a/src/MesApp.Api/Services/MasterCsvKinds.cs +++ b/src/MesApp.Api/Services/MasterCsvKinds.cs @@ -40,7 +40,7 @@ public static class MasterCsvKinds new("Unit", "単位", true, "個・kg・m など"), new("Specification", "規格", false, null), new("Type", "品目区分", false, "Product(製品)/ SemiFinished(半製品)/ Material(部材)"), - new("StandardDefectRate", "標準不良率(%)", false, "0〜100"), + new("StandardDefectRate", "標準不良率(%)", false, "0〜99.99。指図の予定材料をこの率ぶん割り増す"), new("DefaultLocationCode", "既定ロケーション", false, "推奨ロケーションの第一候補。空欄で解除"), new("IsActive", "有効", false, "true / false。falseで無効化"), ]), diff --git a/src/MesApp.Api/Services/MasterCsvService.Import.cs b/src/MesApp.Api/Services/MasterCsvService.Import.cs index 1ace171..772071e 100644 --- a/src/MesApp.Api/Services/MasterCsvService.Import.cs +++ b/src/MesApp.Api/Services/MasterCsvService.Import.cs @@ -144,7 +144,7 @@ private async Task ImportProductsAsync( var unit = reader.RequiredText("Unit", 20); var specification = reader.Text("Specification", product.Specification); var type = reader.Enum("Type", product.Type, CsvEnumLabels.ProductTypes); - var defectRate = reader.Number("StandardDefectRate", product.StandardDefectRate, 0, 100); + var defectRate = reader.Number("StandardDefectRate", product.StandardDefectRate, 0, 99.99m); var defaultLocationId = reader.Reference( "DefaultLocationCode", product.DefaultLocationId, locationIds, "ロケーション"); var isActive = reader.Bool("IsActive", product.IsActive); diff --git a/src/MesApp.Client.Web/Pages/Masters/ProductsTab.razor b/src/MesApp.Client.Web/Pages/Masters/ProductsTab.razor index 6dcb774..7d73590 100644 --- a/src/MesApp.Client.Web/Pages/Masters/ProductsTab.razor +++ b/src/MesApp.Client.Web/Pages/Masters/ProductsTab.razor @@ -34,7 +34,7 @@
    - +
    diff --git a/src/MesApp.Core/Contracts/Masters/MasterContracts.cs b/src/MesApp.Core/Contracts/Masters/MasterContracts.cs index cfedc24..5cb58bc 100644 --- a/src/MesApp.Core/Contracts/Masters/MasterContracts.cs +++ b/src/MesApp.Core/Contracts/Masters/MasterContracts.cs @@ -11,7 +11,8 @@ public record ProductRequest( [Required, MaxLength(20)] string Unit, string? Specification, ProductType Type, - [Range(0, 100)] decimal StandardDefectRate, + /// 標準不良率(%)。予定材料の数量を割り増す(÷(1-率))ため100%は受け付けない + [Range(0, 99.99)] decimal StandardDefectRate, /// 既定の入庫先ロケーション(推奨ロケーション指示の第一候補。D-10-30-03、D-40-40-03) int? DefaultLocationId = null); diff --git a/src/MesApp.Core/Entities/Masters.cs b/src/MesApp.Core/Entities/Masters.cs index 1f635b4..a8ed796 100644 --- a/src/MesApp.Core/Entities/Masters.cs +++ b/src/MesApp.Core/Entities/Masters.cs @@ -20,7 +20,10 @@ public class Product : IDeactivatableMaster public ProductType Type { get; set; } - /// 標準不良率(%。A-40-10-04) + /// + /// 標準不良率(%。A-40-10-04)。指図の展開で予定材料の数量を 原単位×指図数量÷(1-率) に割り増す。 + /// 不良品も部材を消費する(バックフラッシュは良品+不良の数で引く)ため、良品を指図数量だけ得るのに要る部材を見込む + /// public decimal StandardDefectRate { get; set; } /// diff --git a/tests/MesApp.Api.Tests/MasterCsvTests.cs b/tests/MesApp.Api.Tests/MasterCsvTests.cs index c2e05a3..6a4c77e 100644 --- a/tests/MesApp.Api.Tests/MasterCsvTests.cs +++ b/tests/MesApp.Api.Tests/MasterCsvTests.cs @@ -161,7 +161,7 @@ public async Task 英語では列の案内と取込エラーが英語で返り Assert.False(result.Succeeded); Assert.Contains(result.Errors, e => e.Line == 2 && e.Message == "Name is required."); - Assert.Contains(result.Errors, e => e.Line == 3 && e.Message == "StandardDefectRate must be 100 or less ('200')."); + Assert.Contains(result.Errors, e => e.Line == 3 && e.Message == "StandardDefectRate must be 99.99 or less ('200')."); Assert.Contains(result.Errors, e => e.Line == 5 && e.Message == "Item code 'P-003' appears on multiple rows."); } diff --git a/tests/MesApp.Api.Tests/ProductionTests.cs b/tests/MesApp.Api.Tests/ProductionTests.cs index 714e7ea..b631df6 100644 --- a/tests/MesApp.Api.Tests/ProductionTests.cs +++ b/tests/MesApp.Api.Tests/ProductionTests.cs @@ -413,6 +413,31 @@ public async Task 工順未登録の品目の指図は展開できない() Assert.Equal(HttpStatusCode.BadRequest, expanded.StatusCode); } + [Fact] + public async Task 予定材料は親品目の標準不良率ぶん割り増される() + { + using var factory = new ApiFactory(); + using var admin = await TestAuth.CreateAdminClientAsync(factory); + var ctx = await Phase3TestData.SetupAsync(admin); + + // 不良品も部材を使うので、良品10を得るには 2×10÷(1-0.2)=25 の部材が要る(A-40-10-04) + (await admin.PutAsJsonAsync($"/api/products/{ctx.ProductId}", + new ProductRequest("FG-01", "完成品", "個", null, ProductType.Product, 20m))).EnsureSuccessStatusCode(); + var order = await Phase3TestData.CreateReleasedOrderAsync(admin, ctx.ProductId, 10m); + Assert.Equal(25m, order.Materials!.Single().PlannedQuantity); + + // 割り切れないときは小数6桁で切り上げる(2×10÷0.7=28.5714285…) + (await admin.PutAsJsonAsync($"/api/products/{ctx.ProductId}", + new ProductRequest("FG-01", "完成品", "個", null, ProductType.Product, 30m))).EnsureSuccessStatusCode(); + var rounded = await Phase3TestData.CreateReleasedOrderAsync(admin, ctx.ProductId, 10m); + Assert.Equal(28.571429m, rounded.Materials!.Single().PlannedQuantity); + + // ÷(1-率) なので100%は受け付けない + var invalid = await admin.PutAsJsonAsync($"/api/products/{ctx.ProductId}", + new ProductRequest("FG-01", "完成品", "個", null, ProductType.Product, 100m)); + Assert.Equal(HttpStatusCode.BadRequest, invalid.StatusCode); + } + [Fact] public async Task MBOMの消費工程が工順に無い品目の指図は展開できない() { From d77d7d820d8f6f70d12afa5529c177f440907779 Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:13:55 +0900 Subject: [PATCH 04/10] =?UTF-8?q?=E5=BE=AA=E7=92=B0=E3=81=99=E3=82=8BMBOM?= =?UTF-8?q?=EF=BC=88A=E2=86=92B=E2=86=92=E2=80=A6=E2=86=92A=EF=BC=89?= =?UTF-8?q?=E3=82=92=E7=99=BB=E9=8C=B2=E6=99=82=E3=81=AB=E6=8B=92=E5=90=A6?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit これまでは品目自身を子品目にする行だけを拒否しており、2段以上で一周する構成は 単票APIでもCSVでも登録できた。今の展開は1段だけなので処理は止まらないが、作れない品目の 構成になり、多段の所要量展開や逆展開を足したときに無限ループになる。 - 判定を ProductStructurePolicy.FindBomCycle に置き、単票APIとマスタCSV取込の両方から呼ぶ - 置き換える親品目自身の既存明細は判定に入れない - CSVは取り込んだ親品目の明細をその都度判定用に置き換え、同じファイル内の循環も捕まえる - エラーには一周する経路を品目コードで示す - Spec.md 改訂119、利用者ガイド(マスタ)を更新 MES.md: A-40-10-01(MBOM登録) Co-Authored-By: Claude Opus 5.5 --- Spec.md | 3 +- docs/masters.md | 2 +- src/MesApp.Api/Localization/ApiText.en.resx | 3 + .../Policies/ProductStructurePolicy.cs | 55 +++++++++++++++++++ .../Services/MasterCsvService.Import.cs | 10 ++++ .../Services/ProductStructureService.cs | 12 ++++ tests/MesApp.Api.Tests/MasterCsvTests.cs | 21 +++++++ tests/MesApp.Api.Tests/MasterTests.cs | 25 +++++++++ 8 files changed, 129 insertions(+), 2 deletions(-) diff --git a/Spec.md b/Spec.md index 6d35f31..950a924 100644 --- a/Spec.md +++ b/Spec.md @@ -117,6 +117,7 @@ 改訂116: 2026-09-23(3.8節:実績CSVに出荷指示 `shipping-orders`・出荷判定 `shipment-judgments`・出荷実行 `shipments` を追加した。サンプルの実績で出荷だけが画面操作で、製造から出荷までをCSVだけではたどれなかった。判定と出荷で取込の権限が違うため3種別に分ける。出荷判定の登録・承認を `ShipmentJudgmentsController` から `ShipmentJudgmentService` へ移し、単票APIとCSV取込の両方から呼ぶ。出荷指示は後続のCSVから指すため出荷番号の手入力を許す(`SH〜` は自動採番用として拒否)。サンプル `samples/actual-csv/13〜15` を追加) 改訂117: 2026-09-23(3.9節・5.1節・5.2節:MBOMの行に消費工程(`BomItem.RoutingSequence`。親品目の工順の工程順序)を追加した。バックフラッシュが作業指示の工程にかかわらず指図の予定材料をすべて引いていたため、複数工程の品目で工程ごとにバックフラッシュすると部材が工程数ぶん減っていた。バックフラッシュはその作業指示の工程で消費する部材だけを引き、消費する部材の無い工程では拒否する。未指定の行は最終工程で消費し、展開時に予定材料へ最終工程の工程順序を入れて固定する。工順は一括置換で行が作り直されるためIDではなく工程順序で指し、工順に無い工程順序は展開時に拒否する。MBOMのCSVに `RoutingSequence` 列を追加し、サンプル `samples/master-csv/15_bom.csv` は実績サンプルの部材投入に合わせて工程10とした) 改訂118: 2026-09-23(5.1節・5.2節:品目の標準不良率を指図の予定材料に反映するようにした。A-40-10-04(不良率などのMBOM付加情報)として入力できたが、どこにも使われていなかった。予定数量を 原単位×指図数量÷(1-親品目の標準不良率) とする。不良品も部材を消費する(バックフラッシュは良品+不良の数で引く)ため、良品を指図数量だけ得るのに要る部材を見込む。割り切れない値は列の精度(小数6桁)で切り上げる(切り捨てると欠品側にずれる)。÷(1-率) のため標準不良率は100%を受け付けず 0〜99.99 とした(単票API・CSV)。バックフラッシュの消費量は実績(良品+不良)基準のままで変えない) +改訂119: 2026-09-23(5.1節:MBOMの循環(A→B→…→A)を登録時に拒否するようにした。これまでは品目自身を子品目にする行だけを拒否しており、2段以上で一周する構成は単票APIでもCSVでも登録できた。今の展開は1段だけなので処理は止まらないが、作れない品目の構成になり、多段の所要量展開や逆展開を足したときに無限ループになる。判定は `ProductStructurePolicy.FindBomCycle` に置き、単票APIとマスタCSV取込の両方から呼ぶ。置き換える親品目自身の既存明細は判定に入れない。CSVでは取り込んだ親品目の明細をその都度判定用に置き換え、同じファイルの後の行が前の行と循環するのも捕まえる。エラーには一周する経路を品目コードで示す) 参考: みんなのMES(min-MES) https://min-mes.com/ / OSS: https://github.com/mihatama/open-mes-project --- @@ -400,7 +401,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと | SkillMaster(スキル・資格マスタ) | コード、名称、種別(スキル/資格)、有効期限管理要否(F-20-10-01) | | UserSkill(従業員スキル・資格) | ユーザーID、スキル/資格ID、取得日、有効期限、状態(F-20-10-02〜05) | | Product(品目マスタ) | 品目コード、品目名、単位、規格、品目区分(製品/半製品・中間品/部材)、標準不良率(0〜99.99%。指図の予定材料を割り増す。A-40-10-04)、**既定ロケーション**(推奨ロケーション指示の第一候補。D-10-30-03) | -| BomItem(MBOM明細) | 親品目ID、子品目ID(部材)、必要数量(親1単位あたり)、内外製区分、代替部品グループ、**代替部品フラグ**(同一グループ内の主材料でない行。A-40-10)、**消費工程**(工順の工程順序。未指定なら最終工程。B-40-10-09) | +| BomItem(MBOM明細) | 親品目ID、子品目ID(部材)、必要数量(親1単位あたり)、内外製区分、代替部品グループ、**代替部品フラグ**(同一グループ内の主材料でない行。A-40-10)、**消費工程**(工順の工程順序。未指定なら最終工程。B-40-10-09)。品目自身を子品目にする行と、明細をたどって親品目へ戻る循環は登録できない(単票API・CSVで同じ判定。`ProductStructurePolicy.FindBomCycle`) | | Process(工程マスタ) | 工程コード、工程名、工程区分(内製/外注) | | Routing(工順/BOP) | 品目ID、工程順序、工程ID、標準作業時間(**1個あたり**)、標準段取り時間(**1回あたり**)、必要スキルID、**候補設備**・治工具、**作業区**、工程管理項目、チェックリストID、**作業手順書ID**(A-40-20、I-30-20)
    標準時間の予実(3.2節 B-60-10-05)は 段取り時間+作業時間×数量 で予定を出す | | RoutingEquipment(工順の候補設備) | 工順ID、設備ID(同一工順で一意)。同じ工程を複数の装置で実行できる場合に列挙し、差立ではこの中から1台を選ぶ(B-10-20-02) | diff --git a/docs/masters.md b/docs/masters.md index 1ab8f48..3e6d719 100644 --- a/docs/masters.md +++ b/docs/masters.md @@ -84,7 +84,7 @@ next_title: 生産管理

    保存は一括置換です。画面に表示されている明細で既存の構成が丸ごと置き換わります。 1行だけ足したい場合も、既存行を残したまま追加して保存してください。

    -

    品目自身を子品目にすることはできません。

    +

    品目自身を子品目にすることはできません。構成が一周する登録(例:製品の子に半製品、半製品の子に製品)もできません。エラーには一周する経路が表示されます。

    MBOMは、実績入力の**バックフラッシュ**(部材の自動消費)で使われます。 diff --git a/src/MesApp.Api/Localization/ApiText.en.resx b/src/MesApp.Api/Localization/ApiText.en.resx index eb2b511..82ab63b 100644 --- a/src/MesApp.Api/Localization/ApiText.en.resx +++ b/src/MesApp.Api/Localization/ApiText.en.resx @@ -1998,4 +1998,7 @@ 0 to 99.99. Planned materials of an order are increased by this rate + + The MBOM is circular ({0}). + diff --git a/src/MesApp.Api/Policies/ProductStructurePolicy.cs b/src/MesApp.Api/Policies/ProductStructurePolicy.cs index 199d484..ae68b21 100644 --- a/src/MesApp.Api/Policies/ProductStructurePolicy.cs +++ b/src/MesApp.Api/Policies/ProductStructurePolicy.cs @@ -35,4 +35,59 @@ public static IEnumerable CandidateEquipmentIds(IEnumerable? candidate (candidates ?? []) .Concat(representative is { } id ? [id] : []) .Distinct(); + + /// + /// MBOMの循環(A→B→…→A)を探す(A-40-10-01)。親品目の明細を に置き換えたとき、 + /// 子品目から既存の明細をたどって親品目へ戻れるなら、その経路(親品目で始まり親品目で終わる品目IDの並び)を返す。 + /// 循環がなければ null。 + /// + /// 今の展開は1段だけなので循環があっても止まらないが、構成として作れない品目になる。 + /// 多段の所要量展開や逆展開を足したときに無限ループになるため、登録の時点で止める。 + /// の親品目自身の明細は、置き換えられるので見ない + /// + /// + public static IReadOnlyList? FindBomCycle( + IReadOnlyDictionary> childrenByParent, int parentId, IEnumerable childIds) + { + // 幅優先でたどり、見つけた品目の手前を覚えておいて経路を組み立てる + var previous = new Dictionary(); + var queue = new Queue(); + foreach (var child in childIds.Distinct()) + { + if (child == parentId) + { + return [parentId, parentId]; + } + previous[child] = parentId; + queue.Enqueue(child); + } + while (queue.Count > 0) + { + var current = queue.Dequeue(); + if (current == parentId || !childrenByParent.TryGetValue(current, out var next)) + { + continue; + } + foreach (var child in next) + { + if (child == parentId) + { + var path = new List { parentId, current }; + for (var at = current; previous[at] != parentId; at = previous[at]) + { + path.Add(previous[at]); + } + path.Add(parentId); + // 末尾から組んだので、親品目→子品目→…→親品目の順に並べ直す + path.Reverse(1, path.Count - 2); + return path; + } + if (previous.TryAdd(child, current)) + { + queue.Enqueue(child); + } + } + } + return null; + } } diff --git a/src/MesApp.Api/Services/MasterCsvService.Import.cs b/src/MesApp.Api/Services/MasterCsvService.Import.cs index 772071e..5349a5c 100644 --- a/src/MesApp.Api/Services/MasterCsvService.Import.cs +++ b/src/MesApp.Api/Services/MasterCsvService.Import.cs @@ -905,6 +905,10 @@ private async Task ImportBomAsync( { var productIds = await ProductIdsAsync(ct); var existing = await db.BomItems.ToListAsync(ct); + // 循環の判定に使う明細。取り込んだ親品目の分はその都度置き換え、後の行が前の行と循環するのも捕まえる + var edges = existing.GroupBy(b => b.ParentProductId) + .ToDictionary(g => g.Key, g => g.Select(b => b.ChildProductId).ToList()); + var codeById = productIds.ToDictionary(p => p.Value, p => p.Key); foreach (var group in GroupRows(table, "ParentProductCode", errors)) { @@ -961,6 +965,12 @@ private async Task ImportBomAsync( { continue; } + if (ProductStructurePolicy.FindBomCycle(edges, parentId, lines.Select(l => l.ChildProductId)) is { } cycle) + { + parentReader.Fail(ApiText.T("MBOMが循環します({0})。", string.Join(" → ", cycle.Select(id => codeById[id])))); + continue; + } + edges[parentId] = [.. lines.Select(l => l.ChildProductId)]; var current = existing.Where(b => b.ParentProductId == parentId).ToList(); db.BomItems.RemoveRange(current); diff --git a/src/MesApp.Api/Services/ProductStructureService.cs b/src/MesApp.Api/Services/ProductStructureService.cs index 11c6e55..24f4bf3 100644 --- a/src/MesApp.Api/Services/ProductStructureService.cs +++ b/src/MesApp.Api/Services/ProductStructureService.cs @@ -35,6 +35,18 @@ public sealed class ProductStructureService(MesAppDbContext db, IAuditLogger aud return ApiText.T("存在しない子品目IDが含まれています。"); } + var edges = (await db.BomItems.AsNoTracking() + .Select(b => new { b.ParentProductId, b.ChildProductId }) + .ToListAsync(ct)) + .GroupBy(b => b.ParentProductId) + .ToDictionary(g => g.Key, g => g.Select(b => b.ChildProductId).ToList()); + if (ProductStructurePolicy.FindBomCycle(edges, productId, childIds) is { } cycle) + { + var codes = await db.Products.AsNoTracking() + .Where(p => cycle.Contains(p.Id)).ToDictionaryAsync(p => p.Id, p => p.Code, ct); + return ApiText.T("MBOMが循環します({0})。", string.Join(" → ", cycle.Select(id => codes[id]))); + } + var existing = await db.BomItems.Where(b => b.ParentProductId == productId).ToListAsync(ct); db.BomItems.RemoveRange(existing); db.BomItems.AddRange(items.Select(i => new BomItem diff --git a/tests/MesApp.Api.Tests/MasterCsvTests.cs b/tests/MesApp.Api.Tests/MasterCsvTests.cs index 6a4c77e..c791bf6 100644 --- a/tests/MesApp.Api.Tests/MasterCsvTests.cs +++ b/tests/MesApp.Api.Tests/MasterCsvTests.cs @@ -186,6 +186,27 @@ public async Task ShiftJISのCSVと日本語ラベルを取り込める() Assert.Equal(ProductType.Material, product.Type); } + [Fact] + public async Task 循環するMBOMはCSVでも取り込めない() + { + using var factory = new ApiFactory(); + using var client = await TestAuth.CreateAdminClientAsync(factory); + Assert.True((await ImportAsync(client, "products", """ + Code,Name,Unit,Type + FG-01,完成品,個,Product + SF-01,半製品,個,SemiFinished + """)).Succeeded); + + // 同じファイルの後の行が前の行と循環するのも捕まえる(単票APIと同じ判定。Spec.md 7.4) + var result = await ImportAsync(client, "bom", """ + ParentProductCode,ChildProductCode,QuantityPer + FG-01,SF-01,1 + SF-01,FG-01,1 + """); + Assert.False(result.Succeeded); + Assert.Contains(result.Errors, e => e.Line == 3 && e.Message.Contains("SF-01 → FG-01 → SF-01")); + } + [Fact] public async Task MBOMと工順をコード指定のCSVで一括登録できる() { diff --git a/tests/MesApp.Api.Tests/MasterTests.cs b/tests/MesApp.Api.Tests/MasterTests.cs index ef6d7fc..dc851cb 100644 --- a/tests/MesApp.Api.Tests/MasterTests.cs +++ b/tests/MesApp.Api.Tests/MasterTests.cs @@ -75,6 +75,31 @@ public async Task 作業者ロールはマスタ参照はできるが更新は Assert.Equal(HttpStatusCode.Forbidden, write.StatusCode); } + [Fact] + public async Task 循環するMBOMは登録できない() + { + using var factory = new ApiFactory(); + using var admin = await TestAuth.CreateAdminClientAsync(factory); + var fg = await CreateProductAsync(admin, "FG-01", "完成品", ProductType.Product); + var sf = await CreateProductAsync(admin, "SF-01", "半製品", ProductType.SemiFinished); + var rm = await CreateProductAsync(admin, "RM-01", "部材", ProductType.Material); + (await admin.PutAsJsonAsync($"/api/products/{fg.Id}/bom", + new List { new(sf.Id, 1m, MakeOrBuy.InHouse, null) })).EnsureSuccessStatusCode(); + (await admin.PutAsJsonAsync($"/api/products/{sf.Id}/bom", + new List { new(rm.Id, 1m, MakeOrBuy.InHouse, null) })).EnsureSuccessStatusCode(); + + // RM-01 → FG-01 を足すと FG-01 → SF-01 → RM-01 → FG-01 と一周する。経路をそのまま示す + var cyclic = await admin.PutAsJsonAsync($"/api/products/{rm.Id}/bom", + new List { new(fg.Id, 1m, MakeOrBuy.InHouse, null) }); + Assert.Equal(HttpStatusCode.BadRequest, cyclic.StatusCode); + var problem = await cyclic.Content.ReadFromJsonAsync(); + Assert.Contains("RM-01 → FG-01 → SF-01 → RM-01", problem!.Title); + + // 親品目自身の既存明細は置き換えられるので、循環の判定に入れない(SF-01 の子を差し替えるのは循環ではない) + (await admin.PutAsJsonAsync($"/api/products/{sf.Id}/bom", + new List { new(rm.Id, 2m, MakeOrBuy.InHouse, null) })).EnsureSuccessStatusCode(); + } + [Fact] public async Task MBOMと工順を一括登録できる() { From ca9678e953601caa1340536b45fdf73752d4476f Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:20:22 +0900 Subject: [PATCH 05/10] =?UTF-8?q?MBOM=E3=81=AE=E4=BB=A3=E6=9B=BF=E9=83=A8?= =?UTF-8?q?=E5=93=81=E3=82=B0=E3=83=AB=E3=83=BC=E3=83=97=E3=81=AE=E6=95=B4?= =?UTF-8?q?=E5=90=88=E3=82=92=E7=99=BB=E9=8C=B2=E6=99=82=E3=81=AB=E7=A2=BA?= =?UTF-8?q?=E3=81=8B=E3=82=81=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit グループの無い代替部品の行、主材料の無いグループ、主材料が2つ以上あるグループを登録できた。 主材料が無いとバックフラッシュ(代替部品の行は消費しない)がそのグループの部材を何も引かず、 主材料が2つ以上だと代わりになるはずの部材を両方とも原単位ぶん引く。 - 代替部品の行はグループ必須、グループの主材料はちょうど1つ(ProductStructurePolicy.CheckAlternativeGroups) - 単票APIとマスタCSV取込の両方から同じ判定を呼ぶ - グループ名は前後の空白を除いて比べ、その形で保存する - 主材料を2つ並べていた既存テストを、代替部品フラグと代替理由を使う形に直した - Spec.md 改訂120、利用者ガイド(マスタ)を更新 MES.md: A-40-10-04(その他MBOM関連情報:代替部品) Co-Authored-By: Claude Opus 5.5 --- Spec.md | 3 +- docs/masters.md | 1 + src/MesApp.Api/Localization/ApiText.en.resx | 12 ++++++ .../Policies/ProductStructurePolicy.cs | 37 ++++++++++++++++++ .../Services/MasterCsvService.Import.cs | 8 +++- .../Services/ProductStructureService.cs | 13 +++++-- tests/MesApp.Api.Tests/ExecutionTests.cs | 4 +- tests/MesApp.Api.Tests/MasterCsvTests.cs | 22 +++++++++++ tests/MesApp.Api.Tests/MasterTests.cs | 38 +++++++++++++++++++ 9 files changed, 130 insertions(+), 8 deletions(-) diff --git a/Spec.md b/Spec.md index 950a924..47a737e 100644 --- a/Spec.md +++ b/Spec.md @@ -118,6 +118,7 @@ 改訂117: 2026-09-23(3.9節・5.1節・5.2節:MBOMの行に消費工程(`BomItem.RoutingSequence`。親品目の工順の工程順序)を追加した。バックフラッシュが作業指示の工程にかかわらず指図の予定材料をすべて引いていたため、複数工程の品目で工程ごとにバックフラッシュすると部材が工程数ぶん減っていた。バックフラッシュはその作業指示の工程で消費する部材だけを引き、消費する部材の無い工程では拒否する。未指定の行は最終工程で消費し、展開時に予定材料へ最終工程の工程順序を入れて固定する。工順は一括置換で行が作り直されるためIDではなく工程順序で指し、工順に無い工程順序は展開時に拒否する。MBOMのCSVに `RoutingSequence` 列を追加し、サンプル `samples/master-csv/15_bom.csv` は実績サンプルの部材投入に合わせて工程10とした) 改訂118: 2026-09-23(5.1節・5.2節:品目の標準不良率を指図の予定材料に反映するようにした。A-40-10-04(不良率などのMBOM付加情報)として入力できたが、どこにも使われていなかった。予定数量を 原単位×指図数量÷(1-親品目の標準不良率) とする。不良品も部材を消費する(バックフラッシュは良品+不良の数で引く)ため、良品を指図数量だけ得るのに要る部材を見込む。割り切れない値は列の精度(小数6桁)で切り上げる(切り捨てると欠品側にずれる)。÷(1-率) のため標準不良率は100%を受け付けず 0〜99.99 とした(単票API・CSV)。バックフラッシュの消費量は実績(良品+不良)基準のままで変えない) 改訂119: 2026-09-23(5.1節:MBOMの循環(A→B→…→A)を登録時に拒否するようにした。これまでは品目自身を子品目にする行だけを拒否しており、2段以上で一周する構成は単票APIでもCSVでも登録できた。今の展開は1段だけなので処理は止まらないが、作れない品目の構成になり、多段の所要量展開や逆展開を足したときに無限ループになる。判定は `ProductStructurePolicy.FindBomCycle` に置き、単票APIとマスタCSV取込の両方から呼ぶ。置き換える親品目自身の既存明細は判定に入れない。CSVでは取り込んだ親品目の明細をその都度判定用に置き換え、同じファイルの後の行が前の行と循環するのも捕まえる。エラーには一周する経路を品目コードで示す) +改訂120: 2026-09-23(5.1節:MBOMの代替部品グループの整合を登録時に確かめるようにした。グループの無い代替部品の行、主材料の無いグループ、主材料が2つ以上あるグループを登録できた。主材料が無いとバックフラッシュ(代替部品の行を消費しない。3.9節)がそのグループの部材を何も引かず、主材料が2つ以上だと代わりになるはずの部材を両方とも原単位ぶん引く。グループの無い代替部品はどの主材料の代わりかが決まらない。判定は `ProductStructurePolicy.CheckAlternativeGroups` に置き、単票APIとマスタCSV取込の両方から呼ぶ。グループ名は前後の空白を除いて比べ、その形で保存する(空白違いで別グループになるのを防ぐ)。既存のデータは直さない(次にそのMBOMを保存するときに判定される)) 参考: みんなのMES(min-MES) https://min-mes.com/ / OSS: https://github.com/mihatama/open-mes-project --- @@ -401,7 +402,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと | SkillMaster(スキル・資格マスタ) | コード、名称、種別(スキル/資格)、有効期限管理要否(F-20-10-01) | | UserSkill(従業員スキル・資格) | ユーザーID、スキル/資格ID、取得日、有効期限、状態(F-20-10-02〜05) | | Product(品目マスタ) | 品目コード、品目名、単位、規格、品目区分(製品/半製品・中間品/部材)、標準不良率(0〜99.99%。指図の予定材料を割り増す。A-40-10-04)、**既定ロケーション**(推奨ロケーション指示の第一候補。D-10-30-03) | -| BomItem(MBOM明細) | 親品目ID、子品目ID(部材)、必要数量(親1単位あたり)、内外製区分、代替部品グループ、**代替部品フラグ**(同一グループ内の主材料でない行。A-40-10)、**消費工程**(工順の工程順序。未指定なら最終工程。B-40-10-09)。品目自身を子品目にする行と、明細をたどって親品目へ戻る循環は登録できない(単票API・CSVで同じ判定。`ProductStructurePolicy.FindBomCycle`) | +| BomItem(MBOM明細) | 親品目ID、子品目ID(部材)、必要数量(親1単位あたり)、内外製区分、代替部品グループ、**代替部品フラグ**(同一グループ内の主材料でない行。A-40-10)、**消費工程**(工順の工程順序。未指定なら最終工程。B-40-10-09)。品目自身を子品目にする行と、明細をたどって親品目へ戻る循環は登録できない(単票API・CSVで同じ判定。`ProductStructurePolicy.FindBomCycle`)。代替部品グループは主材料(代替部品フラグの無い行)をちょうど1つ持ち、代替部品フラグの行はグループを必須とする(`CheckAlternativeGroups`。グループ名は前後の空白を除いて保存・比較) | | Process(工程マスタ) | 工程コード、工程名、工程区分(内製/外注) | | Routing(工順/BOP) | 品目ID、工程順序、工程ID、標準作業時間(**1個あたり**)、標準段取り時間(**1回あたり**)、必要スキルID、**候補設備**・治工具、**作業区**、工程管理項目、チェックリストID、**作業手順書ID**(A-40-20、I-30-20)
    標準時間の予実(3.2節 B-60-10-05)は 段取り時間+作業時間×数量 で予定を出す | | RoutingEquipment(工順の候補設備) | 工順ID、設備ID(同一工順で一意)。同じ工程を複数の装置で実行できる場合に列挙し、差立ではこの中から1台を選ぶ(B-10-20-02) | diff --git a/docs/masters.md b/docs/masters.md index 3e6d719..94a3225 100644 --- a/docs/masters.md +++ b/docs/masters.md @@ -85,6 +85,7 @@ next_title: 生産管理

    保存は一括置換です。画面に表示されている明細で既存の構成が丸ごと置き換わります。 1行だけ足したい場合も、既存行を残したまま追加して保存してください。

    品目自身を子品目にすることはできません。構成が一周する登録(例:製品の子に半製品、半製品の子に製品)もできません。エラーには一周する経路が表示されます。

    +

    代替部品グループには、主材料(代替部品にチェックしない行)をちょうど1つ入れ、残りを代替部品にします。代替部品にチェックした行にはグループ名が必要です。

    MBOMは、実績入力の**バックフラッシュ**(部材の自動消費)で使われます。 diff --git a/src/MesApp.Api/Localization/ApiText.en.resx b/src/MesApp.Api/Localization/ApiText.en.resx index 82ab63b..2173de3 100644 --- a/src/MesApp.Api/Localization/ApiText.en.resx +++ b/src/MesApp.Api/Localization/ApiText.en.resx @@ -2001,4 +2001,16 @@ The MBOM is circular ({0}). + + A substitute row needs a substitute group (child item '{0}'). + + + Substitute group '{0}' has no primary material (a row that is not a substitute). + + + Substitute group '{0}' has more than one primary material ({1}). Keep one primary and mark the others as substitutes. + + + Parent item '{0}': {1} + diff --git a/src/MesApp.Api/Policies/ProductStructurePolicy.cs b/src/MesApp.Api/Policies/ProductStructurePolicy.cs index ae68b21..9e5e843 100644 --- a/src/MesApp.Api/Policies/ProductStructurePolicy.cs +++ b/src/MesApp.Api/Policies/ProductStructurePolicy.cs @@ -1,3 +1,4 @@ +using MesApp.Api.Localization; using MesApp.Core.Entities; namespace MesApp.Api.Policies; @@ -36,6 +37,42 @@ public static IEnumerable CandidateEquipmentIds(IEnumerable? candidate .Concat(representative is { } id ? [id] : []) .Distinct(); + /// + /// MBOMの代替部品グループの整合(A-40-10-04)。問題があれば日本語の理由を返す。 + /// + /// 代替部品の行は代替部品グループを持つ(どの主材料の代わりかが決まらないと、投入の照合で意味を持たない) + /// グループの主材料(代替部品でない行)はちょうど1つ。無いとバックフラッシュがそのグループの部材を何も引かず、 + /// 2つ以上だと代わりになるはずの部材を両方とも原単位ぶん引く(Spec.md 3.9) + /// + /// グループ名は前後の空白を除いて比べる() + /// + public static string? CheckAlternativeGroups(IEnumerable<(string ChildCode, string? Group, bool IsAlternative)> lines) + { + var normalized = lines.Select(l => (l.ChildCode, Group: NormalizeAlternativeGroup(l.Group), l.IsAlternative)).ToList(); + if (normalized.FirstOrDefault(l => l.IsAlternative && l.Group is null) is { ChildCode: { } orphan }) + { + return ApiText.T("代替部品の行には代替部品グループが必要です(子品目 '{0}')。", orphan); + } + foreach (var group in normalized.Where(l => l.Group is not null).GroupBy(l => l.Group!, StringComparer.Ordinal)) + { + var primaries = group.Where(l => !l.IsAlternative).Select(l => l.ChildCode).ToList(); + if (primaries.Count == 0) + { + return ApiText.T("代替部品グループ '{0}' に主材料(代替部品でない行)がありません。", group.Key); + } + if (primaries.Count > 1) + { + return ApiText.T("代替部品グループ '{0}' に主材料が複数あります({1})。主材料は1つにし、他は代替部品にしてください。", + group.Key, string.Join(", ", primaries)); + } + } + return null; + } + + /// 代替部品グループ名の正規化(前後の空白を除き、空なら未指定)。保存とグループの比較で同じ形にする + public static string? NormalizeAlternativeGroup(string? group) => + string.IsNullOrWhiteSpace(group) ? null : group.Trim(); + /// /// MBOMの循環(A→B→…→A)を探す(A-40-10-01)。親品目の明細を に置き換えたとき、 /// 子品目から既存の明細をたどって親品目へ戻れるなら、その経路(親品目で始まり親品目で終わる品目IDの並び)を返す。 diff --git a/src/MesApp.Api/Services/MasterCsvService.Import.cs b/src/MesApp.Api/Services/MasterCsvService.Import.cs index 5349a5c..5ca5142 100644 --- a/src/MesApp.Api/Services/MasterCsvService.Import.cs +++ b/src/MesApp.Api/Services/MasterCsvService.Import.cs @@ -956,7 +956,7 @@ private async Task ImportBomAsync( ChildProductId = childId!.Value, QuantityPer = quantity!.Value, MakeOrBuy = makeOrBuy, - AlternativeGroup = alternativeGroup, + AlternativeGroup = ProductStructurePolicy.NormalizeAlternativeGroup(alternativeGroup), IsAlternative = isAlternative, RoutingSequence = routingSequence, }); @@ -965,6 +965,12 @@ private async Task ImportBomAsync( { continue; } + if (ProductStructurePolicy.CheckAlternativeGroups( + lines.Select(l => (codeById[l.ChildProductId], l.AlternativeGroup, l.IsAlternative))) is { } alternativeError) + { + parentReader.Fail(ApiText.T("親品目 '{0}':{1}", parentCode, alternativeError)); + continue; + } if (ProductStructurePolicy.FindBomCycle(edges, parentId, lines.Select(l => l.ChildProductId)) is { } cycle) { parentReader.Fail(ApiText.T("MBOMが循環します({0})。", string.Join(" → ", cycle.Select(id => codeById[id])))); diff --git a/src/MesApp.Api/Services/ProductStructureService.cs b/src/MesApp.Api/Services/ProductStructureService.cs index 24f4bf3..7c0ed52 100644 --- a/src/MesApp.Api/Services/ProductStructureService.cs +++ b/src/MesApp.Api/Services/ProductStructureService.cs @@ -28,12 +28,17 @@ public sealed class ProductStructureService(MesAppDbContext db, IAuditLogger aud } var childIds = items.Select(i => i.ChildProductId).ToList(); - var validChildIds = await db.Products - .Where(p => childIds.Contains(p.Id)).Select(p => p.Id).ToListAsync(ct); - if (childIds.Except(validChildIds).Any()) + var childCodes = await db.Products + .Where(p => childIds.Contains(p.Id)).ToDictionaryAsync(p => p.Id, p => p.Code, ct); + if (childIds.Except(childCodes.Keys).Any()) { return ApiText.T("存在しない子品目IDが含まれています。"); } + if (ProductStructurePolicy.CheckAlternativeGroups( + items.Select(i => (childCodes[i.ChildProductId], i.AlternativeGroup, i.IsAlternative))) is { } alternativeError) + { + return alternativeError; + } var edges = (await db.BomItems.AsNoTracking() .Select(b => new { b.ParentProductId, b.ChildProductId }) @@ -55,7 +60,7 @@ public sealed class ProductStructureService(MesAppDbContext db, IAuditLogger aud ChildProductId = i.ChildProductId, QuantityPer = i.QuantityPer, MakeOrBuy = i.MakeOrBuy, - AlternativeGroup = i.AlternativeGroup, + AlternativeGroup = ProductStructurePolicy.NormalizeAlternativeGroup(i.AlternativeGroup), IsAlternative = i.IsAlternative, RoutingSequence = i.RoutingSequence, })); diff --git a/tests/MesApp.Api.Tests/ExecutionTests.cs b/tests/MesApp.Api.Tests/ExecutionTests.cs index 7c6ad37..c391e4d 100644 --- a/tests/MesApp.Api.Tests/ExecutionTests.cs +++ b/tests/MesApp.Api.Tests/ExecutionTests.cs @@ -311,7 +311,7 @@ public async Task MBOMに含まれない品目のロットは投入できない( new List { new(ctx.MaterialId, Phase3TestData.BomQuantityPer, MakeOrBuy.InHouse, "G1"), - new(other.Id, Phase3TestData.BomQuantityPer, MakeOrBuy.InHouse, "G1"), + new(other.Id, Phase3TestData.BomQuantityPer, MakeOrBuy.InHouse, "G1", IsAlternative: true), })).EnsureSuccessStatusCode(); var stillRejected = await admin.PostAsJsonAsync($"/api/work-orders/{workOrderId}/consumptions", new ConsumptionRequest(otherLot.Id, ctx.MaterialLocationId, 5m)); @@ -321,7 +321,7 @@ public async Task MBOMに含まれない品目のロットは投入できない( var newOrder = await Phase3TestData.CreateReleasedOrderAsync(admin, ctx.ProductId, 10m); var accepted2 = await admin.PostAsJsonAsync( $"/api/work-orders/{newOrder.WorkOrders[0].Id}/consumptions", - new ConsumptionRequest(otherLot.Id, ctx.MaterialLocationId, 5m)); + new ConsumptionRequest(otherLot.Id, ctx.MaterialLocationId, 5m, "主材料の欠品")); Assert.Equal(HttpStatusCode.OK, accepted2.StatusCode); Assert.Equal(95m, await Phase3TestData.GetStockQuantityAsync(admin, otherLot.Id)); } diff --git a/tests/MesApp.Api.Tests/MasterCsvTests.cs b/tests/MesApp.Api.Tests/MasterCsvTests.cs index c791bf6..cd60e40 100644 --- a/tests/MesApp.Api.Tests/MasterCsvTests.cs +++ b/tests/MesApp.Api.Tests/MasterCsvTests.cs @@ -207,6 +207,28 @@ public async Task 循環するMBOMはCSVでも取り込めない() Assert.Contains(result.Errors, e => e.Line == 3 && e.Message.Contains("SF-01 → FG-01 → SF-01")); } + [Fact] + public async Task 代替部品グループの整合はCSVでも確かめる() + { + using var factory = new ApiFactory(); + using var client = await TestAuth.CreateAdminClientAsync(factory); + Assert.True((await ImportAsync(client, "products", """ + Code,Name,Unit,Type + FG-01,完成品,個,Product + RM-01,主材料,個,Material + RM-02,代替部材,個,Material + """)).Succeeded); + + // 単票APIと同じ判定(ProductStructurePolicy)。主材料の無いグループは取り込めない + var result = await ImportAsync(client, "bom", """ + ParentProductCode,ChildProductCode,QuantityPer,AlternativeGroup,IsAlternative + FG-01,RM-01,1,GRP-1,true + FG-01,RM-02,1,GRP-1,true + """); + Assert.False(result.Succeeded); + Assert.Contains(result.Errors, e => e.Line == 2 && e.Message.Contains("GRP-1") && e.Message.Contains("FG-01")); + } + [Fact] public async Task MBOMと工順をコード指定のCSVで一括登録できる() { diff --git a/tests/MesApp.Api.Tests/MasterTests.cs b/tests/MesApp.Api.Tests/MasterTests.cs index dc851cb..7000e30 100644 --- a/tests/MesApp.Api.Tests/MasterTests.cs +++ b/tests/MesApp.Api.Tests/MasterTests.cs @@ -100,6 +100,44 @@ public async Task 循環するMBOMは登録できない() new List { new(rm.Id, 2m, MakeOrBuy.InHouse, null) })).EnsureSuccessStatusCode(); } + [Fact] + public async Task 代替部品グループは主材料をちょうど1つ持つ() + { + using var factory = new ApiFactory(); + using var admin = await TestAuth.CreateAdminClientAsync(factory); + var fg = await CreateProductAsync(admin, "FG-01", "完成品", ProductType.Product); + var main = await CreateProductAsync(admin, "RM-01", "主材料", ProductType.Material); + var sub = await CreateProductAsync(admin, "RM-02", "代替部材", ProductType.Material); + + async Task PutAsync(params BomItemRequest[] items) + { + var response = await admin.PutAsJsonAsync($"/api/products/{fg.Id}/bom", items.ToList()); + return response.IsSuccessStatusCode + ? null + : (await response.Content.ReadFromJsonAsync())!.Title; + } + + // グループの無い代替部品は、どの主材料の代わりか決まらない + Assert.Contains("RM-02", await PutAsync( + new(main.Id, 1m, MakeOrBuy.InHouse, null), + new(sub.Id, 1m, MakeOrBuy.InHouse, null, IsAlternative: true))); + // 主材料が無いと、バックフラッシュがグループの部材を何も引かない + Assert.Contains("GRP-1", await PutAsync( + new(main.Id, 1m, MakeOrBuy.InHouse, "GRP-1", IsAlternative: true), + new(sub.Id, 1m, MakeOrBuy.InHouse, "GRP-1", IsAlternative: true))); + // 主材料が2つだと、代わりになるはずの部材を両方引く + Assert.Contains("RM-01, RM-02", await PutAsync( + new(main.Id, 1m, MakeOrBuy.InHouse, "GRP-1"), + new(sub.Id, 1m, MakeOrBuy.InHouse, "GRP-1"))); + + // グループ名は前後の空白を除いて比べ、その形で保存する + Assert.Null(await PutAsync( + new(main.Id, 1m, MakeOrBuy.InHouse, "GRP-1"), + new(sub.Id, 1m, MakeOrBuy.InHouse, " GRP-1 ", IsAlternative: true))); + var bom = await admin.GetFromJsonAsync>($"/api/products/{fg.Id}/bom"); + Assert.All(bom!, b => Assert.Equal("GRP-1", b.AlternativeGroup)); + } + [Fact] public async Task MBOMと工順を一括登録できる() { From 4fb02594aaa80335bb557776ed5b1da82208945e Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:28:25 +0900 Subject: [PATCH 06/10] =?UTF-8?q?MBOM=E3=81=AE=E6=94=B9=E8=A8=82=E3=81=AE?= =?UTF-8?q?=E7=9B=A3=E6=9F=BB=E3=83=AD=E3=82=B0=E3=81=AB=E5=A4=89=E6=9B=B4?= =?UTF-8?q?=E5=89=8D=E5=BE=8C=E3=81=AE=E6=98=8E=E7=B4=B0=E3=82=92=E6=AE=8B?= =?UTF-8?q?=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit これまでは items=件数 だけで、一括置換のため設計変更(A-40-10-05)で何を変えたか追えなかった。 - 変更前後の明細(子品目コード・原単位・内外製・代替部品グループ・代替部品フラグ・消費工程)を new { before, after, reason } で残す。子品目はIDでなくコードで残す - マスタCSV取込でも親品目ごとに同じ形で残す。監査ログは書くたびに保存するため、 取込の途中では書かず、全行の検証が通って保存した後にまとめて書く - Spec.md 改訂121 MES.md: A-40-10-05(設計変更対応) Co-Authored-By: Claude Opus 5.5 --- Spec.md | 2 + .../Services/MasterCsvService.Import.cs | 12 +++++ .../Services/ProductStructureService.cs | 42 ++++++++++++--- tests/MesApp.Api.Tests/AuditLogTests.cs | 51 +++++++++++++++++++ 4 files changed, 100 insertions(+), 7 deletions(-) diff --git a/Spec.md b/Spec.md index 47a737e..e03af57 100644 --- a/Spec.md +++ b/Spec.md @@ -119,6 +119,7 @@ 改訂118: 2026-09-23(5.1節・5.2節:品目の標準不良率を指図の予定材料に反映するようにした。A-40-10-04(不良率などのMBOM付加情報)として入力できたが、どこにも使われていなかった。予定数量を 原単位×指図数量÷(1-親品目の標準不良率) とする。不良品も部材を消費する(バックフラッシュは良品+不良の数で引く)ため、良品を指図数量だけ得るのに要る部材を見込む。割り切れない値は列の精度(小数6桁)で切り上げる(切り捨てると欠品側にずれる)。÷(1-率) のため標準不良率は100%を受け付けず 0〜99.99 とした(単票API・CSV)。バックフラッシュの消費量は実績(良品+不良)基準のままで変えない) 改訂119: 2026-09-23(5.1節:MBOMの循環(A→B→…→A)を登録時に拒否するようにした。これまでは品目自身を子品目にする行だけを拒否しており、2段以上で一周する構成は単票APIでもCSVでも登録できた。今の展開は1段だけなので処理は止まらないが、作れない品目の構成になり、多段の所要量展開や逆展開を足したときに無限ループになる。判定は `ProductStructurePolicy.FindBomCycle` に置き、単票APIとマスタCSV取込の両方から呼ぶ。置き換える親品目自身の既存明細は判定に入れない。CSVでは取り込んだ親品目の明細をその都度判定用に置き換え、同じファイルの後の行が前の行と循環するのも捕まえる。エラーには一周する経路を品目コードで示す) 改訂120: 2026-09-23(5.1節:MBOMの代替部品グループの整合を登録時に確かめるようにした。グループの無い代替部品の行、主材料の無いグループ、主材料が2つ以上あるグループを登録できた。主材料が無いとバックフラッシュ(代替部品の行を消費しない。3.9節)がそのグループの部材を何も引かず、主材料が2つ以上だと代わりになるはずの部材を両方とも原単位ぶん引く。グループの無い代替部品はどの主材料の代わりかが決まらない。判定は `ProductStructurePolicy.CheckAlternativeGroups` に置き、単票APIとマスタCSV取込の両方から呼ぶ。グループ名は前後の空白を除いて比べ、その形で保存する(空白違いで別グループになるのを防ぐ)。既存のデータは直さない(次にそのMBOMを保存するときに判定される)) +改訂121: 2026-09-23(3.1節:MBOMの改訂(A-40-10-05 設計変更)の監査ログに変更前後の明細を残すようにした。これまでは `items=件数` だけで、一括置換のため何を変えたか追えなかった。明細は子品目をIDではなくコードで残す(品目を無効化・改名しても読めるように)。マスタCSV取込では種別ごとの取込ログに加えて親品目ごとに同じ形のログを書く(CSVが追跡の抜け道にならないように)。監査ログは書くたびに保存するため、取込の途中では書かず、全行の検証が通って保存した後にまとめて書く) 参考: みんなのMES(min-MES) https://min-mes.com/ / OSS: https://github.com/mihatama/open-mes-project --- @@ -229,6 +230,7 @@ HSE〔G〕はチェックリスト項目への健康衛生・安全項目の組 - **生産計画変更**[将来拡張]:スケジューラーを介さないMES上での計画変更(A-10-30-02) - **MBOM管理**:MBOM登録(A-40-10-01)、中間品(追加品目)登録(A-40-10-02)、内外製区分登録(A-40-10-03)、不良率・代替部品等の付加情報(A-40-10-04)、設計変更対応(A-40-10-05) - **BOP/BOE管理**:工順(BOP)・設備情報(BOE)の登録・付加情報管理(A-40-20-01〜02、I-10-20-02、I-30-20-02、I-30-20-13)、工程変更対応(A-40-20-03、I-50-30-01/03)、設計変更反映時の在庫・生産状況確認(J-40-40-01/03) + - MBOMの改訂は監査ログに**変更前後の明細**(子品目コード・原単位・内外製・代替部品グループ・代替部品フラグ・消費工程)を残す。単票APIでもマスタCSV取込でも同じ形で、CSVでは親品目ごとに1件書く - 設計変更(MBOM・工順の改訂)の影響は品目マスタ画面で確認する。進行中の指図と、部材の在庫・進行中指図の予定数量を並べる - **展開済みの指図には改訂が届かない**(5.7節のスナップショット)。改訂後の条件で作り直すなら指図の取消と再作成が要る。未展開(未承認・承認済)の指図は展開時に改訂後の値を使う - 部材は現行MBOMと進行中指図のスナップショットの**和集合**で並べる。改訂で外したのに進行中指図がまだ必要としている部材と、その在庫が見えるようにするため diff --git a/src/MesApp.Api/Services/MasterCsvService.Import.cs b/src/MesApp.Api/Services/MasterCsvService.Import.cs index 5ca5142..ef2b417 100644 --- a/src/MesApp.Api/Services/MasterCsvService.Import.cs +++ b/src/MesApp.Api/Services/MasterCsvService.Import.cs @@ -20,6 +20,12 @@ private sealed class ImportCounter /// 取り込めたが伝えたいこと(エラーと違いロールバックしない。CsvImportResult.Warnings) public List Warnings { get; } = []; + + /// + /// 保存の後に書く個別の監査ログ(対象の種類・ID・内容)。監査ログは書くたびに保存するため、 + /// 取込の途中で書くと検証前の変更まで保存してしまう。全行の検証が通って保存した後にまとめて書く + /// + public List<(string TargetType, string TargetId, object Detail)> Audits { get; } = []; } public async Task ImportAsync( @@ -113,6 +119,10 @@ private async Task ImportOneAsync( await db.SaveChangesAsync(ct); await auditLogger.LogAsync("Master", "CsvImport", kind.Kind, null, detail: $"rows={table.Rows.Count}, created={counter.Created}, updated={counter.Updated}", ct: ct); + foreach (var (targetType, targetId, detail) in counter.Audits) + { + await auditLogger.LogAsync("Master", "Update", targetType, targetId, detail: detail, ct: ct); + } } return new CsvFileImportCount(counter.Created, counter.Updated) { Warnings = counter.Warnings }; } @@ -979,6 +989,8 @@ private async Task ImportBomAsync( edges[parentId] = [.. lines.Select(l => l.ChildProductId)]; var current = existing.Where(b => b.ParentProductId == parentId).ToList(); + // 設計変更の追跡(A-40-10-05)は単票APIと同じ形で残す。CSVから改訂すると中身が追えない、にしない + counter.Audits.Add(("Bom", parentId.ToString(), ProductStructureService.BomChangeDetail(current, lines, codeById))); db.BomItems.RemoveRange(current); db.BomItems.AddRange(lines); if (current.Count > 0) diff --git a/src/MesApp.Api/Services/ProductStructureService.cs b/src/MesApp.Api/Services/ProductStructureService.cs index 7c0ed52..63ba9e8 100644 --- a/src/MesApp.Api/Services/ProductStructureService.cs +++ b/src/MesApp.Api/Services/ProductStructureService.cs @@ -47,14 +47,13 @@ public sealed class ProductStructureService(MesAppDbContext db, IAuditLogger aud .ToDictionary(g => g.Key, g => g.Select(b => b.ChildProductId).ToList()); if (ProductStructurePolicy.FindBomCycle(edges, productId, childIds) is { } cycle) { - var codes = await db.Products.AsNoTracking() + var cycleCodes = await db.Products.AsNoTracking() .Where(p => cycle.Contains(p.Id)).ToDictionaryAsync(p => p.Id, p => p.Code, ct); - return ApiText.T("MBOMが循環します({0})。", string.Join(" → ", cycle.Select(id => codes[id]))); + return ApiText.T("MBOMが循環します({0})。", string.Join(" → ", cycle.Select(id => cycleCodes[id]))); } var existing = await db.BomItems.Where(b => b.ParentProductId == productId).ToListAsync(ct); - db.BomItems.RemoveRange(existing); - db.BomItems.AddRange(items.Select(i => new BomItem + var lines = items.Select(i => new BomItem { ParentProductId = productId, ChildProductId = i.ChildProductId, @@ -63,13 +62,42 @@ public sealed class ProductStructureService(MesAppDbContext db, IAuditLogger aud AlternativeGroup = ProductStructurePolicy.NormalizeAlternativeGroup(i.AlternativeGroup), IsAlternative = i.IsAlternative, RoutingSequence = i.RoutingSequence, - })); + }).ToList(); + var codeIds = existing.Select(b => b.ChildProductId).Except(childCodes.Keys).ToList(); + var codes = childCodes.Concat(await db.Products.AsNoTracking() + .Where(p => codeIds.Contains(p.Id)).ToDictionaryAsync(p => p.Id, p => p.Code, ct)) + .ToDictionary(); + var detail = BomChangeDetail(existing, lines, codes); + db.BomItems.RemoveRange(existing); + db.BomItems.AddRange(lines); await db.SaveChangesAsync(ct); - await auditLogger.LogAsync("Master", "Update", "Bom", productId.ToString(), - detail: $"items={items.Count}", ct: ct); + await auditLogger.LogAsync("Master", "Update", "Bom", productId.ToString(), detail: detail, ct: ct); return null; } + /// + /// MBOM改訂の監査ログの内容(変更前後の明細。A-40-10-05 設計変更)。 + /// 一括置換なので件数だけでは何を変えたか追えない。子品目はIDでなくコードで残す(品目を無効化・改名しても読めるように)。 + /// 単票APIとマスタCSV取込の両方で同じ形にする + /// + internal static object BomChangeDetail( + IEnumerable before, IEnumerable after, IReadOnlyDictionary codeById) + { + object[] Snapshot(IEnumerable lines) => + [ + .. lines.OrderBy(b => codeById[b.ChildProductId], StringComparer.Ordinal).Select(b => new + { + child = codeById[b.ChildProductId], + quantityPer = b.QuantityPer, + makeOrBuy = b.MakeOrBuy.ToString(), + alternativeGroup = b.AlternativeGroup, + isAlternative = b.IsAlternative, + routingSequence = b.RoutingSequence, + }), + ]; + return new { before = Snapshot(before), after = Snapshot(after), reason = (string?)null }; + } + /// 工順(BOP)の一括置換(工程変更 A-40-20-03、I-50-30 も本処理で反映) public async Task ReplaceRoutingAsync(int productId, List steps, CancellationToken ct) { diff --git a/tests/MesApp.Api.Tests/AuditLogTests.cs b/tests/MesApp.Api.Tests/AuditLogTests.cs index 33a4466..826a141 100644 --- a/tests/MesApp.Api.Tests/AuditLogTests.cs +++ b/tests/MesApp.Api.Tests/AuditLogTests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using System.Net; using System.Net.Http.Json; +using System.Text.Json; using MesApp.Core.Constants; using MesApp.Core.Contracts.Audit; using MesApp.Core.Contracts.Common; @@ -157,6 +158,56 @@ await admin.PutAsJsonAsync($"/api/stocktakes/{stocktake.Id}/counts", Assert.Contains("90", logs.Items[0].Detail); } + [Fact] + public async Task MBOMの改訂は変更前後の明細が監査ログに残る() + { + using var factory = new ApiFactory(); + using var admin = await TestAuth.CreateAdminClientAsync(factory); + var ctx = await Phase3TestData.SetupAsync(admin); // FG-01 の MBOM:RM-01 × 2 + var rm2 = await MasterTests.CreateProductAsync(admin, "RM-02", "梱包材", ProductType.Material); + + // 設計変更(A-40-10-05)は一括置換なので、件数だけでは何を変えたか追えない + (await admin.PutAsJsonAsync($"/api/products/{ctx.ProductId}/bom", new List + { + new(ctx.MaterialId, 3m, MakeOrBuy.InHouse, null), + new(rm2.Id, 1m, MakeOrBuy.InHouse, null, RoutingSequence: 2), + })).EnsureSuccessStatusCode(); + var api = await LatestBomLogAsync(); + using (var detail = JsonDocument.Parse(api.Detail!)) + { + var before = detail.RootElement.GetProperty("before"); + var after = detail.RootElement.GetProperty("after"); + Assert.Equal(1, before.GetArrayLength()); + Assert.Equal("RM-01", before[0].GetProperty("child").GetString()); + Assert.Equal(2m, before[0].GetProperty("quantityPer").GetDecimal()); + Assert.Equal(["RM-01", "RM-02"], after.EnumerateArray().Select(l => l.GetProperty("child").GetString())); + Assert.Equal(3m, after[0].GetProperty("quantityPer").GetDecimal()); + Assert.Equal(2, after[1].GetProperty("routingSequence").GetInt32()); + } + + // CSVから改訂しても同じ形で残る(CSVが追跡の抜け道にならない) + Assert.True((await Phase3TestData.ImportCsvAsync(admin, "masters/csv/bom", """ + ParentProductCode,ChildProductCode,QuantityPer + FG-01,RM-02,4 + """)).Succeeded); + var csv = await LatestBomLogAsync(); + Assert.NotEqual(api.Id, csv.Id); + using (var detail = JsonDocument.Parse(csv.Detail!)) + { + Assert.Equal(2, detail.RootElement.GetProperty("before").GetArrayLength()); + var after = detail.RootElement.GetProperty("after"); + Assert.Equal(1, after.GetArrayLength()); + Assert.Equal(4m, after[0].GetProperty("quantityPer").GetDecimal()); + } + + async Task LatestBomLogAsync() + { + var logs = await admin.GetFromJsonAsync>( + $"/api/audit-logs?targetType=Bom&targetId={ctx.ProductId}&action=Update"); + return logs!.Items[0]; // 新しい順 + } + } + /// /// 埋め戻しはSQLiteの既存DBだけが対象(他のプロバイダーは列の追加後に作られるため過去行が無い)。 /// 実DB(MESAPP_TEST_PROVIDER)で流したときは何も検査せずに通る(xUnit 2 は実行時にスキップできない) From 6eb57dbcc6df9d2916c0fde72b3869b3267c111f Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:33:29 +0900 Subject: [PATCH 07/10] =?UTF-8?q?Opus=205.5=20=E3=81=AE=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E9=96=8B=E5=A7=8B=E3=81=AB=E5=90=88=E3=82=8F=E3=81=9B=E3=81=A6?= =?UTF-8?q?=E3=82=AA=E3=83=BC=E3=82=B1=E3=82=B9=E3=83=88=E3=83=AC=E3=83=BC?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3=E9=81=8B=E7=94=A8=E3=82=92=E8=A6=8B?= =?UTF-8?q?=E7=9B=B4=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - L1/L2 をモデルではなく同じ Opus 5.5 の effort で分ける(Orchestration.md §3.1・§3.4 新設) - 単価表を更新し、Sonnet 5 の単価の誤記を訂正(§2.1) - モデル・effort はセッション途中で変えない(キャッシュがモデルごとのため。§4.2) - タスクカードに effort 欄を追加、CLAUDE.md の要点に1行追加 Co-Authored-By: Claude Opus 5.5 --- .claude/commands/task-card.md | 3 +- CLAUDE.md | 1 + Orchestration.md | 60 +++++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/.claude/commands/task-card.md b/.claude/commands/task-card.md index fc751ec..311a5c1 100644 --- a/.claude/commands/task-card.md +++ b/.claude/commands/task-card.md @@ -25,10 +25,11 @@ allowed-tools: Read, Grep, Glob, Bash - 受入条件(DoD): <機械的に検証できる形で。ビルド・テスト以外の固有条件を書く> - 参照: Spec.md §x.y / MES.md No.X-XX-XX-XX / docs-dev/CodeMap.md の該当行 - 想定層: L1(設計判断あり) / L2(仕様確定済の実装) / L3(機械的) +- effort: xhigh / high / medium / low(Orchestration.md §3.4 の表から選ぶ) - 想定変更ファイル数: N ``` ## 自己チェック(出力の最後に1行で) - 変更対象が3ファイルを超える、または「調査で確定」が2項目以上 → **粒度が粗い。分割案を併記する。** -- 認証/在庫更新/実績・原価計算/CSV取込/データモデル変更を含む → 想定層は L1 とし、その理由を書く。 +- 認証/在庫更新/実績・原価計算/CSV取込/データモデル変更を含む → 想定層は L1・effort は xhigh とし、その理由を書く。 diff --git a/CLAUDE.md b/CLAUDE.md index c2e8c98..d0b367b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -125,6 +125,7 @@ Entity(`Core/Entities`)→ `MesAppDbContext` の `DbSet` と `Configurations ## 進め方の要点(詳細は Orchestration.md) - 1セッション=1タスク。無関係な作業に移るときは `/clear`、同じファイル群を触るなら継続 +- モデルは Opus 5.5 で統一し、層は effort で分ける(L1 設計=high、高リスク領域=xhigh、L2 実装=medium、定型=low)。モデル・effort はセッション途中で変えない - 探索は Glob → Grep(`-n`・パス限定)→ 該当行±40行の Read。1タスクあたり読込1,500行・Grep 8回まで - **同じエラーで2回失敗したら3回目を同じやり方で試さない**。前提(変更対象・受入条件)を疑う - 機械的に確認できることは build / test / grep で確認する。推測で「直った」と言わない diff --git a/Orchestration.md b/Orchestration.md index 5003ed6..a642fea 100644 --- a/Orchestration.md +++ b/Orchestration.md @@ -1,7 +1,12 @@ # Claude Code オーケストレーション運用仕様書 プロダクト名:Parallel Factory MES -版: 1.0(2026-08-22 制定) +版: 1.1(2026-09-23 改訂。1.0 は 2026-08-22 制定) + +| 版 | 日付 | 内容 | +|:--|:--|:--| +| 1.1 | 2026-09-23 | Claude Opus 5.5 の提供開始に合わせて見直し。単価表を更新(Sonnet 5 の誤記も訂正)。L2 の既定を「別モデル」から「同じ Opus 5.5 を低い effort で」に変更し、effort を層ごとの主レバーにした(§2.1・§2.4・§3.1・§3.3・§3.4・§4.2・§8) | +| 1.0 | 2026-08-22 | 制定 | 対象: 本リポジトリにおける Claude Code を用いた開発作業すべて --- @@ -36,13 +41,19 @@ Claude Code の使用量(トークン/使用枠)を削減しつつ、成 ## 2. コスト構造(なぜ節約できるのか) ### 2.1 モデル単価 -| モデル | モデルID | 入力 $/1M | 出力 $/1M | -|:--|:--|--:|--:| -| Claude Opus 5 | `claude-opus-5` | $5.00 | $25.00 | -| Claude Sonnet 5 | `claude-sonnet-5` | $3.00 | $15.00 | -| Claude Haiku 4.5 | `claude-haiku-4-5` | $1.00 | $5.00 | +| モデル | モデルID | 入力 $/1M | 出力 $/1M | 文脈長 | 本書での扱い | +|:--|:--|--:|--:|--:|:--| +| **Claude Opus 5.5** | `claude-opus-5-5` | $4.00 | $20.00 | 1M | **L1・L2 の既定** | +| Claude Opus 5 | `claude-opus-5` | $5.00 | $25.00 | 1M | 使わない(5.5 の方が安く新しい) | +| Claude Sonnet 5 | `claude-sonnet-5` | $2.00 | $10.00 | 1M | L2 の選択肢(§3.4 の条件つき) | +| Claude Haiku 4.5 | `claude-haiku-4-5` | $1.00 | $5.00 | 200K | 広域の走査だけ(§4.5) | + +キャッシュ書込は入力単価の約 1.25 倍。キャッシュ読取は Opus 5.5 で $0.20/1M(入力の 1/20)。**先頭文脈を変えずにセッションを継続すると、入力コストは 1/10 以下に落ちる**。キャッシュは**モデルごと**に持たれるため、途中でモデルを切り替えると次のターンは全量が書込扱いになる(§4.2)。 -キャッシュ読取は入力単価の約 0.1 倍、キャッシュ書込は約 1.25 倍。**先頭文脈を変えずにセッションを継続すると、入力コストは概ね 1/10 に落ちる**。 +Fast mode(Opus 5.5 で $8 / $40、標準の2倍)は速度を買う機能で節約にはならない。待ち時間が問題になる場面以外では使わない。 + +#### effort(思考の深さ) +Opus 5.5 は思考を切れない。深さとトークン消費は **effort**(`low` / `medium` / `high` / `xhigh` / `max`)で調整する。API の既定は `medium` で、Opus 5 の既定(`high`)より1段低い。**既定に任せず、タスクの層に合わせて明示する**(§3.1・§3.4)。 ### 2.2 会話は毎ターン全量が再送される N ターン目の入力は「それまでの全履歴」である。したがって 1 セッションの総入力トークンは概ね**ターン数の二乗**に比例する。 @@ -59,7 +70,7 @@ N ターン目の入力は「それまでの全履歴」である。したがっ | MES.md | 518行 | 該当業務Noのみ grep | | docs/*.md | 3,321行 | 該当ファイルのみ | -コードベース全体を1回舐めるだけで Opus 入力 $2.5 相当が飛ぶ。**探索の規律が最大の効き目を持つ**。 +コードベース全体を1回舐めるだけで Opus 5.5 の入力 $2 相当が飛び、以降の毎ターンの再送にも乗る。**探索の規律が最大の効き目を持つ**。 ### 2.4 レバー別の期待効果(推定値・実測で更新すること) | レバー | 削減率 | 品質への影響 | @@ -68,19 +79,22 @@ N ターン目の入力は「それまでの全履歴」である。したがっ | 探索規律(§4.3) | 20〜40% | ↑ 無関係な情報に引きずられない | | 出力フィルタ(§4.4) | 5〜15% | → 変化なし | | L3(非LLM)優先(§3.2) | 5〜10% | ↑ 決定論的で確実 | -| L2 ルーティング(§3.3) | 10〜20% | 条件付き(§5.1 DoD と §5.2 エスカレーションで担保) | +| effort の層別指定(§3.4) | 10〜30% | → 設計判断は下げないので変化なし。L2 を下げすぎると手戻りで逆転(§5.2 で担保) | +| L2 の別モデル化(§3.4) | 0〜10% | 条件付き。Opus 5.5 と Sonnet 5 の単価差は2倍しかなく、キャッシュ分断と手戻りで消えやすい | --- ## 3. 役割モデル(オーケストレーション) ### 3.1 3層構造 -| 層 | 担当 | 使用モデル | 責務 | やらないこと | +| 層 | 担当 | 使用モデル / effort | 責務 | やらないこと | |:--|:--|:--|:--|:--| -| **L1 オーケストレーター** | メインセッション | Opus 5 | 分解・設計判断・タスクカード発行・受入判定・統合 | 大量のコードを自分で書かない/全文を読まない | -| **L2 ワーカー** | 別セッション or サブエージェント | Sonnet 5 | 仕様が確定した実装、定型追加、文書追記 | 設計判断・仕様変更の独断 | +| **L1 オーケストレーター** | メインセッション | Opus 5.5 / `high`(高リスク領域は `xhigh`) | 分解・設計判断・タスクカード発行・受入判定・統合 | 大量のコードを自分で書かない/全文を読まない | +| **L2 ワーカー** | 別セッション | Opus 5.5 / `medium`(定型は `low`) | 仕様が確定した実装、定型追加、文書追記 | 設計判断・仕様変更の独断 | | **L3 メカニカル** | ツール実行のみ | なし(**トークン0**) | ビルド、テスト、grep、置換、EF migration 生成、整形 | 判断 | +1.0 では L1 と L2 を**モデル**で分けていた。1.1 からは**同じ Opus 5.5 の effort** で分ける。Opus 5.5 は Opus 5 より2割安く、Sonnet 5 との差は2倍まで縮んだ。新しい上位モデルを低い effort で使う方が、下位モデルを高い effort で使うより品質あたりの消費が少ないことが多い。モデルが1つならキャッシュも分断されない。 + ### 3.2 大原則 > **L3 で済むことを LLM にさせない。L2 で済むことを L1 にさせない。** > ただし「済むかどうか」の判定は L1 が行う。判定を誤ると手戻りが発生し、節約分は消える。 @@ -100,6 +114,21 @@ N ターン目の入力は「それまでの全履歴」である。したがっ | 「どこで使われているか」調査 | L3 → 不足時のみ L2 | まず grep。§4.5 の条件を満たす場合のみサブエージェント | | ビルドエラー修正 | L2(2回失敗で L1 へ) | §5.2 | +### 3.4 effort とモデルの選び方 +| 状況 | 設定 | +|:--|:--| +| §3.3 で L1 に振った類型(データモデル・認証・在庫・実績/原価・CSV取込) | Opus 5.5 / `xhigh` | +| 上記以外の設計判断・タスクカード作成・受入判定 | Opus 5.5 / `high` | +| 仕様確定済みの実装(Controller + テスト、画面タブ追加) | Opus 5.5 / `medium` | +| 定型追加・文書追記・`/add-master` 等の手順どおりの作業 | Opus 5.5 / `low` | +| L2 で同じエラーに2回失敗した | effort を1段上げて L1 として扱う(§5.2)。同じ effort で3回目を試さない | + +**規則** +- effort は**セッションの最初に決め、途中で変えない**(途中の変更はキャッシュを捨てる)。段が変わるなら新しいセッションにする。 +- `max` は使わない。`xhigh` で2回失敗したときは effort ではなくタスクカードの前提を疑う(§5.2)。 +- **Sonnet 5 を L2 に使ってよいのは**、仕様・変更対象・受入条件がカードで確定し、既存の見本ファイルを真似るだけの作業に限る。L1 と同じセッションで切り替えない(キャッシュがモデルごとのため)。手戻りが1回でも出た類型は Opus 5.5 に戻す。 +- 効果は §7 の記録で確かめる。「安いモデル・低い effort にしたのに手戻りで総量が増えた」類型は1段戻す。 + --- ## 4. 実行プロトコル @@ -114,7 +143,7 @@ N ターン目の入力は「それまでの全履歴」である。したがっ - 変更禁止: <例: Migrations/ 配下、既存API契約、DbContext のスキーマ> - 受入条件(DoD): <機械的に検証できる形で箇条書き> - 参照: Spec.md §x.y / MES.md No.X-XX-XX-XX / docs/xxx.md -- 想定層: L1 / L2 / L3 +- 想定層: L1 / L2 / L3(effort: xhigh / high / medium / low。§3.4) - 想定変更ファイル数: N ``` @@ -130,6 +159,7 @@ N ターン目の入力は「それまでの全履歴」である。したがっ | 次のタスクが同じファイル群を触る | 継続(キャッシュ読取 0.1倍の恩恵を受ける) | | 30ターンを超えた | 受入条件を確認して打ち切り、残りを新カードに切り出す | | 作業を続けたいが文脈が長い | `/compact`(継続に文脈が本当に必要な場合のみ) | +| モデルか effort を変えたい | 新しいセッション(同じセッションで変えるとキャッシュが無駄になる) | `/clear` はキャッシュを捨てる操作でもある。**「無関係なら clear、関係あるなら継続」**が判断基準であり、機械的な頻繁 clear は逆効果。 @@ -178,6 +208,8 @@ dotnet test tests/MesApp.Api.Tests -v q --nologo 2>&1 | Select-String -Pattern " - すでに文脈がある作業の続き - 実装の分担(統合コストがトークン・品質の両面で上回る) +**起動するときのモデル**: 結論だけを返す走査(Explore)は Haiku 4.5 か Sonnet 5 を指定してよい(走査の生データを高い単価で読まない)。判断を含む調査は親と同じ Opus 5.5 のままにする。 + ### 4.6 計画と実装の分離 1. L1 が計画を立て、タスクカードに落とす 2. 人間が承認する(唯一かつ最も安い品質関門) @@ -280,7 +312,7 @@ dotnet test tests/MesApp.Api.Tests -v q --nologo 2>&1 | Select-String -Pattern " ## 8. アンチパターン(禁止事項) -1. **節約目的でモデルを一律ダウングレードする** — 手戻りが増え、総消費量はむしろ増える +1. **節約目的でモデルや effort を一律に下げる** — 手戻りが増え、総消費量はむしろ増える。下げるのは §3.4 の表に従い、層ごとに行う 2. **「まず全体を把握して」から始める** — 全文読込は 50万トークン級(§2.3) 3. **1セッションで無関係なタスクを連続実行する** — 履歴再送が二乗で効く(§2.2) 4. **同じ失敗を3回試す** — 2回で必ずエスカレーション(§5.2) From 5903e39b2b495157cf1e353adfb3d154503f16f5 Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:45:09 +0900 Subject: [PATCH 08/10] =?UTF-8?q?MBOM=E6=94=B9=E8=A8=82=EF=BC=88=E6=B6=88?= =?UTF-8?q?=E8=B2=BB=E5=B7=A5=E7=A8=8B=E3=83=BB=E6=A8=99=E6=BA=96=E4=B8=8D?= =?UTF-8?q?=E8=89=AF=E7=8E=87=E3=83=BB=E4=BB=A3=E6=9B=BF=E9=83=A8=E5=93=81?= =?UTF-8?q?=E3=83=BB=E5=BE=AA=E7=92=B0=EF=BC=89=E3=81=AB=E5=90=88=E3=82=8F?= =?UTF-8?q?=E3=81=9B=E3=81=A6=E3=82=B5=E3=83=B3=E3=83=97=E3=83=AB=E3=81=A8?= =?UTF-8?q?=E6=96=87=E6=9B=B8=E3=82=92=E7=9B=B4=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - サンプルの説明:MBOMの部材は工程10で消費すること、標準不良率による予定材料の割り増し、 部材を使わない工程で Backflush=true にすると取り込めないこと - 利用者ガイド:サンプルの図5の予定材料の数量を割り増し後の値に、帳票(作業指示書に載る部材)、 用語(バックフラッシュは予定材料基準)、マスタのCSV(RoutingSequence 列)、 部材投入の代替理由の説明(予定材料にない品目は投入できない、という既存の誤りも直す) - CSVの列の案内(Backflush・AlternativeGroup・IsAlternative)と英訳 - CodeMap に ProductStructurePolicy の新しい判定を追記 - Spec.md 5.7節に予定材料の割り増しと消費工程の固定を追記(改訂122) MES.md: A-40-10-01/04/05、B-10-30-04、B-40-10-09 Co-Authored-By: Claude Opus 5.5 --- Spec.md | 2 ++ docs-dev/CodeMap.md | 2 +- docs/execution.md | 2 +- docs/masters.md | 1 + docs/reference.md | 2 +- docs/reports.md | 4 ++-- docs/walkthrough.md | 8 ++++---- samples/actual-csv/README.md | 6 ++++-- samples/master-csv/README.md | 4 +++- src/MesApp.Api/Localization/ApiText.en.resx | 11 +++++++---- src/MesApp.Api/Services/ActualCsvKinds.cs | 2 +- src/MesApp.Api/Services/MasterCsvKinds.cs | 4 ++-- 12 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Spec.md b/Spec.md index e03af57..5a9718e 100644 --- a/Spec.md +++ b/Spec.md @@ -120,6 +120,7 @@ 改訂119: 2026-09-23(5.1節:MBOMの循環(A→B→…→A)を登録時に拒否するようにした。これまでは品目自身を子品目にする行だけを拒否しており、2段以上で一周する構成は単票APIでもCSVでも登録できた。今の展開は1段だけなので処理は止まらないが、作れない品目の構成になり、多段の所要量展開や逆展開を足したときに無限ループになる。判定は `ProductStructurePolicy.FindBomCycle` に置き、単票APIとマスタCSV取込の両方から呼ぶ。置き換える親品目自身の既存明細は判定に入れない。CSVでは取り込んだ親品目の明細をその都度判定用に置き換え、同じファイルの後の行が前の行と循環するのも捕まえる。エラーには一周する経路を品目コードで示す) 改訂120: 2026-09-23(5.1節:MBOMの代替部品グループの整合を登録時に確かめるようにした。グループの無い代替部品の行、主材料の無いグループ、主材料が2つ以上あるグループを登録できた。主材料が無いとバックフラッシュ(代替部品の行を消費しない。3.9節)がそのグループの部材を何も引かず、主材料が2つ以上だと代わりになるはずの部材を両方とも原単位ぶん引く。グループの無い代替部品はどの主材料の代わりかが決まらない。判定は `ProductStructurePolicy.CheckAlternativeGroups` に置き、単票APIとマスタCSV取込の両方から呼ぶ。グループ名は前後の空白を除いて比べ、その形で保存する(空白違いで別グループになるのを防ぐ)。既存のデータは直さない(次にそのMBOMを保存するときに判定される)) 改訂121: 2026-09-23(3.1節:MBOMの改訂(A-40-10-05 設計変更)の監査ログに変更前後の明細を残すようにした。これまでは `items=件数` だけで、一括置換のため何を変えたか追えなかった。明細は子品目をIDではなくコードで残す(品目を無効化・改名しても読めるように)。マスタCSV取込では種別ごとの取込ログに加えて親品目ごとに同じ形のログを書く(CSVが追跡の抜け道にならないように)。監査ログは書くたびに保存するため、取込の途中では書かず、全行の検証が通って保存した後にまとめて書く) +改訂122: 2026-09-23(5.7節「指図展開時のマスタ固定」に、予定材料の標準不良率による割り増しと消費工程の固定(改訂117・118)を追記した。あわせてマスタCSV・実績CSVの列の案内(`AlternativeGroup`・`IsAlternative`・`Backflush`)、サンプルの説明、利用者ガイド(帳票・用語・マスタのCSV・部材投入)を改訂117〜121に合わせた) 参考: みんなのMES(min-MES) https://min-mes.com/ / OSS: https://github.com/mihatama/open-mes-project --- @@ -539,6 +540,7 @@ DBはバックエンド(MesApp.Api)のみが保持し、既定はSQLiteと - **指図展開時のマスタ固定**:工順(BOP)とMBOMは改訂され上書きされるため、**製造指図の工程展開時点の値を実績側へ固定**する。以降にマスタが改訂されても、既に展開された指図の製造条件と照合条件は変わらない - 工順 → `WorkOrder`(標準作業時間・標準段取り時間・必要スキル・工程管理項目・チェックリスト)。差立のスキル照合(F-20-30-01)はこのスナップショットを使う - MBOM → `ManufacturingOrderMaterial`(予定材料)。部材投入の照合(B-30-20-01)とバックフラッシュ(B-40-10-09)はこの予定材料を基準にする + - 予定数量は親品目の標準不良率で割り増し(原単位×指図数量÷(1-率))、消費工程は未指定なら展開時の最終工程に解決して固定する。バックフラッシュはその作業指示の工程を消費工程とする行だけを引き、作業指示書にもその行だけを載せる - 改訂を仕掛中の指図へ反映したい場合は、指図を展開し直す(マスタ側に有効期間や版を持たせる方式は採らない。実績側スナップショットのほうが「当時どの条件で作れと指示されたか」を直接説明できるため) - **MBOMの部品切替を有効日/失効日で持つ方式は採らない**(切替前後の両方の行を保持し、失効日・有効日で切り替える一般的な方式)。理由は上と同じで、マスタ側に期間を持たせても「その指図が展開された時点でどちらの部品が有効だったか」は**展開時刻と有効日の突き合わせを毎回やり直さないと分からない**のに対し、予定材料(`ManufacturingOrderMaterial`)へ固定すれば当時の指示がそのまま残るため。部材投入の照合(3.9節)も日付の解釈を持たずに済む - ただしこの方式では、**切替日を事前に登録しておく運用(設計変更の予告。A-40-10-05)ができない**。当面は切替日にMBOMを差し替え、仕掛中の指図は必要に応じて展開し直す運用とする。予告運用が必要になった場合は、マスタに有効期間を持たせるのではなく**「切替予定」を別に持って切替日にMBOMへ適用する**形で[将来拡張]する(実績側スナップショットの方針を崩さないため) diff --git a/docs-dev/CodeMap.md b/docs-dev/CodeMap.md index 7f92e40..aeb6db1 100644 --- a/docs-dev/CodeMap.md +++ b/docs-dev/CodeMap.md @@ -119,7 +119,7 @@ | ロット使用可否(投入・引当・出荷の共通判定) | `Api/Policies/LotUsabilityPolicy.cs` | Spec.md 3.9。ステータス・有効期限の条件は**ここだけ**に置く。呼び先は `WorkOrderExecutionService.AddConsumptionAsync`(投入)/`InventoryService.AllocateFefoAsync`(FEFO)/`ShippingService.ShipAsync`(出荷) | | 製造条件の逸脱判定 | `Api/Policies/ControlItemDeviationPolicy.cs` | Spec.md 5.7。基準は**マスタ現在値ではなく作業指示のスナップショット**(`WorkOrderControlItem`)。数値なし・上下限なしは判定せず`null`のまま(`false`にしない)。呼び先は `WorkOrderExecutionService.AddDataRecordsAsync` | | 直(シフト)の時間帯判定 | `Api/Policies/ShiftSchedulePolicy.cs` | Spec.md 5.7。日跨ぎ(`EndTime <= StartTime`)・重なり判定・時刻→直の解決・**製造日の境界またぎの警告**(`CheckBusinessDateBoundary`。拒否ではなく `ShiftResponse.BoundaryWarning` で返す)。単票APIとCSV取込の両方から通す。重なり判定は**0時で切って区間に開いてから突き合わせる**(開始・終了の大小比較だと 22:00〜06:00 と 05:00〜09:00 の重なりを見落とす)。判定の単体テストは `Tests/ShiftSchedulePolicyTests.cs`(1440分の総当たりを期待値にした網羅テストで等価性を固定) | -| 工順・品目から参照できるマスタ | `Api/Policies/ProductStructurePolicy.cs` | Spec.md 5.7。工順の作業区(最下段かつ有効)・作業手順書(有効)・品目の既定ロケーション(有効)・候補設備(代表設備を含める)。呼び先は `ProductStructureService` / `ProductsController` と `MasterCsvService.Import` の `ImportProductsAsync`・`ImportRoutingAsync`。`Tests/MasterTests.cs` / `MasterCsvTests.cs` | +| 工順・品目から参照できるマスタ | `Api/Policies/ProductStructurePolicy.cs` | Spec.md 5.7。工順の作業区(最下段かつ有効)・作業手順書(有効)・品目の既定ロケーション(有効)・候補設備(代表設備を含める)・**MBOMの循環(`FindBomCycle`)と代替部品グループの整合(`CheckAlternativeGroups`)**。呼び先は `ProductStructureService` / `ProductsController` と `MasterCsvService.Import` の `ImportProductsAsync`・`ImportRoutingAsync`・`ImportBomAsync`。`Tests/MasterTests.cs` / `MasterCsvTests.cs` | | 部材投入の照合(予定材料) | `Api/Policies/MaterialIssuePolicy.cs` | Spec.md 3.9・5.7。基準はMBOMの現在値ではなく**指図の予定材料**。呼び先は `WorkOrderExecutionService.AddConsumptionAsync` | | 作業指示ステータス変更(+状態履歴) | `Api/Services/WorkOrderStatusService.cs`
    `Core/Entities/Production.cs`: WorkOrderStatusHistory | Spec.md 5.2。`WorkOrder.Status` を**直接代入しない**。履歴は `GET api/work-orders/{id}/status-history` | | システム管理者を失わない | `Api/Policies/LastAdminPolicy.cs` | Spec.md 3.6。有効なシステム管理者が0人になる無効化・降格を拒否する。呼び先は `UsersController.Update`(1件ずつ判定)/`MasterCsvService.Import.ImportUsersAsync`(**全行の適用後**に判定。行順で引き継ぎを弾かないため)。`Tests/MasterTests.cs` / `MasterCsvTests.cs` | diff --git a/docs/execution.md b/docs/execution.md index fd582e4..e9a9d1a 100644 --- a/docs/execution.md +++ b/docs/execution.md @@ -152,7 +152,7 @@ next_title: 物流・在庫管理
    1. 投入ロットを選びます。ロット番号はスキャンして検索できます。棚は選んだ在庫のものが使われます。
    2. 数量を入力します。
    3. -
    4. 指図の予定材料にない品目(代替部品)を投入するときは代替理由が必須です。
    5. +
    6. 予定材料のうち代替部品の行(MBOMで代替部品にした部材)を投入するときは代替理由が必須です。
    7. 投入を記録を押します。在庫が引き落とされ、投入実績に残ります。
    diff --git a/docs/masters.md b/docs/masters.md index 94a3225..74aad8f 100644 --- a/docs/masters.md +++ b/docs/masters.md @@ -302,6 +302,7 @@ MBOMは、実績入力の**バックフラッシュ**(部材の自動消費) 明細を持つマスタは、**同じキーの行をまとめて1件**として扱い、**その明細を丸ごと置き換えます**。 - **MBOM**:`ParentProductCode`(親品目コード)が同じ行が、その親のMBOMになります。 + `RoutingSequence` に部材を使う工程の工程順序を書きます(空なら最終工程)。代替部品グループのルールと循環の禁止は、画面から登録したときと同じです。 - **工順**:`ProductCode`(品目コード)が同じ行が、その品目の工順になります。 - **チェックリスト**:`Code` が同じ行が、1つのチェックリストの項目になります。 diff --git a/docs/reference.md b/docs/reference.md index 11d3364..16766e5 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -116,7 +116,7 @@ next_title: 困ったときは | 承認しないと展開できない | 製造指図は「承認済」でのみ工程展開できます | | 工程の順序は強制しない | 前工程が終わっていなくても後工程に着手できます。着手順は差立で管理します | | 最終工程で在庫計上 | 工順の最後の工程の実績登録時に、良品数が産出ロットとして入庫されます | -| バックフラッシュはMBOM基準 | MBOM × (良品数 + 不良数) を先入れ先出しで自動消費します | +| バックフラッシュは予定材料基準 | 指図の予定材料のうち、その工程で使う部材を 原単位 × (良品数 + 不良数) だけ先入れ先出しで自動消費します(代替部品は引きません) | | ピッキングは先入れ先出し | 有効期限を優先して自動引当されます | | 出荷には出荷判定が必要 | 承認済みの「可」または「特採」判定がないと出荷実行できません | | 承認は単段階 | 各種承認は1回の承認操作で確定します(多段階ワークフローはありません) | diff --git a/docs/reports.md b/docs/reports.md index dfa5434..6d42e4e 100644 --- a/docs/reports.md +++ b/docs/reports.md @@ -16,7 +16,7 @@ next_title: ロールと権限 | 帳票 | どこから出すか | 内容 | |---|---|---| -| 作業指示書 | 作業指示 一覧/製造指図 詳細 の **指示書** | 指示番号・指図番号・品目・工程・計画数・担当者・設備・構成部品(MBOM) | +| 作業指示書 | 作業指示 一覧/製造指図 詳細 の **指示書** | 指示番号・指図番号・品目・工程・計画数・担当者・設備・この工程で使う部材(指図の予定材料) | | 現品票(ラベル) | 受入/在庫照会/トレーサビリティ の **現品票** | 品目・数量・製造日/受入日・有効期限・ステータス・グレードと、**ロット番号のバーコード** | | 検査成績書 | 検査詳細の **検査成績書** | 検査項目ごとの規格値・測定値・判定 | | 出荷伝票 | 出荷管理の **出荷伝票** | 出荷先・予定日・明細 | @@ -75,4 +75,4 @@ next_title: ロールと権限 - **受入したらすぐ現品票を印刷して貼る。** 以降のピッキング照合・検査・トレースがすべてスキャンで進みます。 - **ピッキングは必ず照合してから実行する。** 一致/不一致の表示は目視確認用で、不一致でも実行ボタンは押せてしまいます。 -- **作業指示書を工程に配る。** 構成部品(MBOM)が載っているので、部材の取り違え防止になります。 +- **作業指示書を工程に配る。** その工程で使う部材(代替部品を含む)が載っているので、部材の取り違え防止になります。 diff --git a/docs/walkthrough.md b/docs/walkthrough.md index 239a7d6..a7d67d4 100644 --- a/docs/walkthrough.md +++ b/docs/walkthrough.md @@ -240,9 +240,9 @@ MBOMと工順の登録方法は、[マスタ管理の品目・MBOM・工順](mas SMP-FG-001-20PR-40 最終検査 10台 SMP-FG-001-30PR-50 梱包 10台 産出ロット FG1000-S001最終工程の良品が、このロットで入庫する -予定材料(MBOM×10台で固定) -SF-2000 10・ギアセット 10・シャフト 10 -Oリング 20(代替可)・ボルト 40・潤滑油 0.5 L +予定材料(MBOM×10台÷(1−1.5%)で固定) +SF-2000 10.15・ギアセット 10.15・シャフト 10.15 +Oリング 20.30(代替可)・ボルト 40.61・潤滑油 0.51 L 予定にない品目は投入できない 製造指図の状態 @@ -271,7 +271,7 @@ MBOMと工順の登録方法は、[マスタ管理の品目・MBOM・工順](mas
    製造指図 SMP-FG-001 の詳細画面。予定材料7品目と、工程展開でできた作業指示3件が表示されている -
    製造指図の詳細。予定材料と、工程展開でできた作業指示が並ぶ。各行から段取り・実績入力・指示書の印刷へ進める
    +
    製造指図の詳細。予定材料と、工程展開でできた作業指示が並ぶ。予定数量はギアポンプの標準不良率 1.5% ぶん割り増され、部材はどれも組立(工程10)で使う。各行から段取り・実績入力・指示書の印刷へ進める
    **差立**では、作業指示ごとに作業者・設備・着手順を割り当てます。作業者には工順の必要スキルが照合され、 diff --git a/samples/actual-csv/README.md b/samples/actual-csv/README.md index c649ed0..ed28835 100644 --- a/samples/actual-csv/README.md +++ b/samples/actual-csv/README.md @@ -57,5 +57,7 @@ GET /api/actuals/csv/receiving/template … ヘッダーだけのCSV - 出荷実行には、その出荷指示を対象にした**承認済みの出荷判定(可・特採)**が要ります。判定の無い指示・保留の指示を 出荷実行CSVに書くと、そのファイルは取り込めません。 - `DV-03`(校正期限切れ)を `DeviceCode` に書くと、その検査は取り込めません。 -- 部材はバックフラッシュ(`Backflush=true`)でも消費できます。ただし代替部品は消費されない - (主材料だけを引く)ので、代替部品を使ったときは投入CSVで理由とともに投入してください。 +- 部材はバックフラッシュ(`Backflush=true`)でも消費できます。引くのは**その工程で使う部材だけ**で、 + サンプルのMBOMでは部材をすべて最初の工程(`Sequence=10`)で使います。部材を使わない工程(20・30)の行を + `Backflush=true` にすると、その行は取り込めません。また代替部品は消費されない(主材料だけを引く)ので、 + 代替部品を使ったときは投入CSVで理由とともに投入してください。 diff --git a/samples/master-csv/README.md b/samples/master-csv/README.md index a2d9d30..d84b836 100644 --- a/samples/master-csv/README.md +++ b/samples/master-csv/README.md @@ -38,7 +38,7 @@ RM-3001 ハウジング鋳造品 | 12 | `12_inspection-items.csv` | 検査項目・基準 | 規格値あり/なし、受入・工程内・完成品・サンプル検査 | | 13 | `13_control-items.csv` | 工程管理項目 | 指示値と許容範囲(製造条件の逸脱判定に使う) | | 14 | `14_inspection-devices.csv` | 検査機・測定器 | 校正期限切れの機器を1台含む(システム管理者のみ取込可) | -| 15 | `15_bom.csv` | 品目・MBOM・工順 | FG-1000 と SF-2000 のMBOM。Oリングに代替部品あり | +| 15 | `15_bom.csv` | 品目・MBOM・工順 | FG-1000 と SF-2000 のMBOM。Oリングに代替部品あり。部材はどれも最初の工程(工程10)で消費する | | 16 | `16_work-procedures.csv` | 作業手順書 | 手順を本文に書く例と、所在だけを書く例(システム管理者のみ取込可) | | 17 | `17_routing.csv` | 品目・MBOM・工順 | 候補設備・作業区・治工具・スキル・チェックリスト・手順書を紐づけた工順 | | 18 | `18_users.csv` | ユーザー | 各ロールの担当者。作業場所・所属・直つき(システム管理者のみ取込可) | @@ -66,6 +66,8 @@ RM-3001 ハウジング鋳造品 ## 試せる業務のポイント - `RM-3007`(耐油Oリング)は `RM-3004` の代替部品です。投入するときは理由の入力が求められます +- `FG-1000` の標準不良率は 1.5%、`SF-2000` は 2% です。製造指図を展開すると、予定材料がこの率ぶん割り増されます + (例:ギアポンプ10台の指図で、ギアセットの予定数量は 10 ÷ (1 − 0.015) = 10.152285) - `14_inspection-devices.csv` の `DV-03` は校正期限切れです。検査実績の測定器に選ぶと登録できません - `SF-2000` の機械加工は `EQ-01` と `EQ-05` のどちらでも作業できます(候補設備) - `op003` は夜勤(20:00〜翌05:00)の作業者です。直別の集計を試せます diff --git a/src/MesApp.Api/Localization/ApiText.en.resx b/src/MesApp.Api/Localization/ApiText.en.resx index 2173de3..73ff611 100644 --- a/src/MesApp.Api/Localization/ApiText.en.resx +++ b/src/MesApp.Api/Localization/ApiText.en.resx @@ -1380,8 +1380,8 @@ Substitute part - - true / false. Consuming a true row requires recording a reason + + true / false. A true row requires AlternativeGroup, and consuming it requires recording a reason Routing (BOP) @@ -1704,8 +1704,8 @@ Backflush - - true consumes planned materials × (good + defect) automatically by FIFO + + true consumes the planned materials used at this step (quantity per × (good + defect)) first-in first-out (substitutes are not consumed) Defects by reason @@ -2013,4 +2013,7 @@ Parent item '{0}': {1} + + Exactly one primary material (IsAlternative=false) per group + diff --git a/src/MesApp.Api/Services/ActualCsvKinds.cs b/src/MesApp.Api/Services/ActualCsvKinds.cs index e5bf0f5..dca7088 100644 --- a/src/MesApp.Api/Services/ActualCsvKinds.cs +++ b/src/MesApp.Api/Services/ActualCsvKinds.cs @@ -101,7 +101,7 @@ public static class ActualCsvKinds new("StartedAt", "開始日時", true, DateTimeNote + "。この時刻で直を決める"), new("EndedAt", "終了日時", false, DateTimeNote), new("OutputLocationCode", "入庫先ロケーションコード", false, "最終工程で良品があるときは必須"), - new("Backflush", "バックフラッシュ", false, "true で予定材料×(良品+不良)を先入れ先出しで自動消費"), + new("Backflush", "バックフラッシュ", false, "true でこの工程で使う予定材料を 原単位×(良品+不良) だけ先入れ先出しで自動消費(代替部品は引かない)"), new("Defects", "不良理由別の内訳", false, "不良理由コード=数量 をセミコロン区切り(DR-02=2;DR-03=1)。合計は不良数以下"), ]), MesRoleGroups.ShopFloorRecord), new(new CsvKindInfo(DataRecords, "製造条件データ", false, diff --git a/src/MesApp.Api/Services/MasterCsvKinds.cs b/src/MesApp.Api/Services/MasterCsvKinds.cs index d1f15b6..2d7fe83 100644 --- a/src/MesApp.Api/Services/MasterCsvKinds.cs +++ b/src/MesApp.Api/Services/MasterCsvKinds.cs @@ -161,8 +161,8 @@ public static class MasterCsvKinds new("ChildProductCode", "子品目コード", true, null), new("QuantityPer", "必要数量(親1単位)", true, "0より大きい数値"), new("MakeOrBuy", "内外製区分", false, "InHouse(内製)/ Outsourced(外注)"), - new("AlternativeGroup", "代替部品グループ", false, null), - new("IsAlternative", "代替部品", false, "true / false。trueの行を投入するには理由の記録が必要"), + new("AlternativeGroup", "代替部品グループ", false, "グループの主材料(IsAlternative=false)はちょうど1つ"), + new("IsAlternative", "代替部品", false, "true / false。trueの行はAlternativeGroupが必須で、投入するには理由の記録が必要"), new("RoutingSequence", "消費工程(工程順序)", false, "親品目の工順の工程順序。空なら最終工程。バックフラッシュはこの工程で部材を引く"), ]), new(Routing, "工順(BOP)", false, From 099768dadef89895ad309e13bcdf7558ea170224 Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:45:21 +0900 Subject: [PATCH 09/10] =?UTF-8?q?=E5=AE=9F=E7=B8=BECSV=E3=82=B5=E3=83=B3?= =?UTF-8?q?=E3=83=97=E3=83=AB=E3=81=AE=E8=AA=AC=E6=98=8E=E3=81=A7=E3=80=81?= =?UTF-8?q?=E5=8F=96=E3=82=8A=E8=BE=BC=E3=82=81=E3=81=AA=E3=81=84=E5=8D=98?= =?UTF-8?q?=E4=BD=8D=E3=82=92=E8=A1=8C=E3=81=A7=E3=81=AF=E3=81=AA=E3=81=8F?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AB=E7=9B=B4=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1行でもエラーがあると全件取り消されるため。 Co-Authored-By: Claude Opus 5.5 --- samples/actual-csv/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/actual-csv/README.md b/samples/actual-csv/README.md index ed28835..62e3bde 100644 --- a/samples/actual-csv/README.md +++ b/samples/actual-csv/README.md @@ -59,5 +59,5 @@ GET /api/actuals/csv/receiving/template … ヘッダーだけのCSV - `DV-03`(校正期限切れ)を `DeviceCode` に書くと、その検査は取り込めません。 - 部材はバックフラッシュ(`Backflush=true`)でも消費できます。引くのは**その工程で使う部材だけ**で、 サンプルのMBOMでは部材をすべて最初の工程(`Sequence=10`)で使います。部材を使わない工程(20・30)の行を - `Backflush=true` にすると、その行は取り込めません。また代替部品は消費されない(主材料だけを引く)ので、 + `Backflush=true` にすると、そのファイルは取り込めません。また代替部品は消費されない(主材料だけを引く)ので、 代替部品を使ったときは投入CSVで理由とともに投入してください。 From 6ed0253d73f3dd90dd020b43bfbd9003329d3152 Mon Sep 17 00:00:00 2001 From: msmsrep <113223770+msmsrep@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:58:23 +0900 Subject: [PATCH 10/10] =?UTF-8?q?=E4=BD=9C=E6=A5=AD=E6=8C=87=E7=A4=BA?= =?UTF-8?q?=E6=9B=B8=E3=81=AE=E5=BF=85=E8=A6=81=E6=95=B0=E9=87=8F=E3=82=92?= =?UTF-8?q?=E4=BA=88=E5=AE=9A=E6=9D=90=E6=96=99=E3=81=8B=E3=82=89=E5=87=BA?= =?UTF-8?q?=E3=81=97=E3=80=81=E6=8C=87=E5=9B=B3=E8=A9=B3=E7=B4=B0=E3=81=A8?= =?UTF-8?q?=E4=BD=9C=E6=A5=AD=E6=8C=87=E7=A4=BA=E6=9B=B8=E3=81=AE=E7=94=BB?= =?UTF-8?q?=E9=9D=A2=E5=86=99=E7=9C=9F=E3=82=92=E6=92=AE=E3=82=8A=E7=9B=B4?= =?UTF-8?q?=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 作業指示書の必要数量を 原単位×計画数 で出していたため、標準不良率による割り増し(改訂118)が 抜け、指図の予定材料(例:10.152285)と食い違っていた。予定材料の予定数量を、指図数量に対する 作業指示の計画数の割合で按分して出す。 画面写真は、サンプルを取り込んだ新しいDBで完了承認まで進めて撮り直した。 - docs/assets/walkthrough/order-detail.webp:予定数量の割り増しと消費工程の列が写る - docs/assets/intro/print-wo.webp:見出しが「この工程で使う部材(予定材料)」、代替部品グループの列 あわせて代替テキストと画像の寸法を直した。 MES.md: B-10-30-04(作業指示書) Co-Authored-By: Claude Opus 5.5 --- docs/assets/intro/print-wo.webp | Bin 37774 -> 35328 bytes docs/assets/walkthrough/order-detail.webp | Bin 65314 -> 70728 bytes docs/intro.html | 2 +- docs/walkthrough.md | 2 +- .../Pages/Print/WorkInstruction.razor | 12 +++++++++++- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/assets/intro/print-wo.webp b/docs/assets/intro/print-wo.webp index ddfb30472b6961caeb9da6bc51eead375444c886..eb02a89bee88a17ef205af4a9c3617d7eb066b6e 100644 GIT binary patch literal 35328 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�|2= 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 diff --git a/docs/assets/walkthrough/order-detail.webp b/docs/assets/walkthrough/order-detail.webp index 4649f64a1788d3a8861aa37e11dde302e2379ccf..0ac5092de55adaf3d60b472d01576ad643a4d4fe 100644 GIT binary patch literal 70728 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 z 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

    kRY?V6a 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 c3a紙の指示書と現品票も、
    そのまま印刷して現場へ

    f^w}@>*3`K(rg;stcVTsUO-vzz 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

    - + } @@ -78,6 +78,7 @@ else private WorkOrderResponse? _workOrder; private List _materials = []; + private decimal _orderQuantity; protected override async Task OnParametersSetAsync() { @@ -90,9 +91,18 @@ else var finalSequence = order?.WorkOrders .Where(w => w.Status != WorkOrderStatus.Canceled) .Max(w => (int?)w.RoutingSequence); + _orderQuantity = order?.Order.Quantity ?? 0; var sequence = _workOrder.RoutingSequence; _materials = [.. (order?.Materials ?? []) .Where(m => m.RoutingSequence == sequence || (m.RoutingSequence is null && sequence == finalSequence))]; } } + + /// + /// 計画数分の必要数量。予定材料の予定数量(標準不良率で割り増し済み。Spec.md 5.2)を、 + /// 指図数量に対するこの作業指示の計画数の割合で按分する。原単位×計画数で出すと割り増しが抜け、指図の予定材料と食い違う + /// + private decimal RequiredQuantity(OrderMaterialResponse line) => + _orderQuantity == 0 ? line.QuantityPer * _workOrder!.PlannedQuantity + : line.PlannedQuantity * _workOrder!.PlannedQuantity / _orderQuantity; }
    @L["子品目"]@L["品目名"]@L["必要数量(計画数分)"]@L["内外製"]
    @L["子品目"]@L["品目名"]@L["必要数量(計画数分)"]@L["代替部品グループ"]
    @line.ChildProductCode@line.ChildProductName@line.ProductCode@line.ProductName @(line.QuantityPer * _workOrder.PlannedQuantity)@EnumLabels.Of(line.MakeOrBuy)@(line.AlternativeGroup ?? "-")
    @line.ProductCode @line.ProductName@(line.QuantityPer * _workOrder.PlannedQuantity)@RequiredQuantity(line) @(line.AlternativeGroup ?? "-")