陈清红
2025-04-14 880f3c0257eeb8c37761d484258fdd102a369a19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
Quintiq file version 2.0
#parent: #root
StaticMethod RefreshOfflinePlan (
  MacroPlan macroPlan
)
{
  TextBody:
  [*
    macroPlan.OfflinePlanTable( relflush );
    
    opt := macroPlan.OfflinePlanTable( relnew, SaveDateTime := DateTime::ActualTime() );
    
    // 生成下线计划表
    traverse ( macroPlan, Unit, u, u.HasCapacityTypeTime() 
    //           and u.Name() = "eMotor Assy (France)" // 测试本地场景时可以过滤
    //           and u.Name() = "DL-MoMo"              // 测试实际场景时可以过滤
              ) {
      // 创建产线行
      opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "", Type := "0" );
      
      traverse ( u, Operation, o ) {
        traverse ( o, PeriodTaskOperation.NewSupply, ns ) {
          // 找行
          oprQuantity := select( opt, OfflinePlanRow, tempOPR, tempOPR.ProductionLine() = u.ID() and tempOPR.ProductID() = ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID() and tempOPR.Type() = "1" );
          oprOrder    := select( opt, OfflinePlanRow, tempOPR, tempOPR.ProductionLine() = u.ID() and tempOPR.ProductID() = ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID() and tempOPR.Type() = "2" );
          if ( isnull( oprQuantity ) and isnull( oprOrder ) ) {
            oprQuantity := opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID(), Type := "1", Notes := ns.AsProductionSupply().ProductInStockingPoint_MP().Product_MP().Notes() );
            oprOrder    := opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID(), Type := "2" );
          }
          
          // 找列
          opc := select( opt, OfflinePlanColumn, tempOPC, tempOPC.ColumnDate() = ns.Start().Date() );
          if ( isnull( opc ) ) {
            opc := opt.OfflinePlanColumn( relnew, ColumnDate := ns.Start().Date() );
          }
          
          // 赋值单元格
          cellQuantity := oprQuantity.OfflinePlanCell( relnew, Value := [String]ns.Quantity().Round( 0 ), Shift := ns.PeriodTask_MP().UnitPeriod().astype( UnitPeriodTimeBase ).ShiftPattern().Name() );
          cellQuantity.OfflinePlanColumn( relset, opc );
          cellOrder := oprOrder.OfflinePlanCell( relnew, 
    //                                             Value := "单号" + [String]ns.Quantity().Round( 0 ) + "_" + [String]( ns.ProductInStockingPointInPeriodPlanningLeaf().InventoryLevelEnd() - ns.ProductInStockingPointInPeriodPlanningLeaf().MinInventoryLevel() ),
                                                 Value := [String]ns.Quantity().Round( 0 ),
                                                 InventoryWeight := ns.ProductInStockingPointInPeriodPlanningLeaf().InventoryLevelEnd() - ns.ProductInStockingPointInPeriodPlanningLeaf().MinInventoryLevel() );
          cellOrder.OfflinePlanColumn( relset, opc );
        }
      }
      
      // 创建总量行
      opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "3" );
      // 创建班次行
      opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "4" );
      // 创建班次开始时间行
      opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "5" );
      // 创建班次结束时间行
      opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "6" );
    }
    
    // 创建产品列&类型列
    productOPC := opt.OfflinePlanColumn( relnew, ColumnDate := macroPlan.StartOfPlanning().Date() - 2 );
    typeOPC    := opt.OfflinePlanColumn( relnew, ColumnDate := macroPlan.StartOfPlanning().Date() - 1 );
    traverse ( opt, OfflinePlanRow, opr ) {
      if ( opr.Type() = "0" ) {
        productLineCell := opr.OfflinePlanCell( relnew, Value := opr.ProductionLine() );
        productLineCell.OfflinePlanColumn( relset, productOPC );
      } else if( opr.Type() = "1" ) {
        productCell := opr.OfflinePlanCell( relnew, Value := opr.ProductID() + ifexpr( opr.Notes() = "", "", "-" + opr.Notes() ) );
        productCell.OfflinePlanColumn( relset, productOPC );
        typeCell    := opr.OfflinePlanCell( relnew, Value :=  "Quantity" );
        typeCell.OfflinePlanColumn( relset, typeOPC );
      } else if ( opr.Type() = "2" ) {
        typeCell    := opr.OfflinePlanCell( relnew, Value :=  "Order" );
        typeCell.OfflinePlanColumn( relset, typeOPC );
      } else if ( opr.Type() = "3" ) {
        totalCell := opr.OfflinePlanCell( relnew, Value := "合计" );
        totalCell.OfflinePlanColumn( relset, productOPC );
        totalCell := opr.OfflinePlanCell( relnew, Value :=  "总量" );
        totalCell.OfflinePlanColumn( relset, typeOPC );
      } else if ( opr.Type() = "4" ) {
        shiftCell := opr.OfflinePlanCell( relnew, Value :=  "班次" );
        shiftCell.OfflinePlanColumn( relset, typeOPC );
      } else if ( opr.Type() = "5" ) {
        shiftStartDateCell := opr.OfflinePlanCell( relnew, Value :=  "班次开始时间" );
        shiftStartDateCell.OfflinePlanColumn( relset, typeOPC );
      } else if ( opr.Type() = "6" ) {
        shiftEndDateCell := opr.OfflinePlanCell( relnew, Value :=  "班次结束时间" );
        shiftEndDateCell.OfflinePlanColumn( relset, typeOPC );
      }
    }
    
    // 补全总量&班次&班次开始时间&班次结束时间
    totalOPRs          := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "3" );
    shiftOPRs          := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "4" );
    shiftStartDateOPRs := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "5" );
    shiftEndDateOPRs   := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "6" );
    traverse ( opt, OfflinePlanColumn, opc, opc.OfflinePlanCell( relsize ) > 0 and opc.ColumnDate() >= macroPlan.StartOfPlanning().Date() ) {
      // 补全总量
      traverse ( totalOPRs, Elements, totalOPR ) {
        total     := sum( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = totalOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1", [Real]tempOPC.Value() );
        totalCell := totalOPR.OfflinePlanCell( relnew, Value := [String]total );
        totalCell.OfflinePlanColumn( relset, opc );
      }
      
      // &班次
      traverse ( shiftOPRs, Elements, shiftOPR ) {
        shift := select( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = shiftOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1" ); 
        if ( not isnull( shift ) ) {
          shiftCell := shiftOPR.OfflinePlanCell( relnew, Value := shift.Shift() );
          shiftCell.OfflinePlanColumn( relset, opc );
        }
      }
      
      // 班次开始时间
      traverse ( shiftStartDateOPRs, Elements, ssdOPR ) {
        shift := select( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = ssdOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1" ); 
        if ( not isnull( shift ) ) {
          startDate     := guard( minselect( macroPlan, ShiftPattern.ShiftDayTime, tempSDT, tempSDT.ShiftPattern().Name() = shift.Shift(), tempSDT.Sequence() ).StartDateTime().Format( "H:m" ), "" );
          startDateCell := ssdOPR.OfflinePlanCell( relnew, Value := startDate );
          startDateCell.OfflinePlanColumn( relset, opc );
        }
      }
      
      // 班次结束时间
      traverse ( shiftEndDateOPRs, Elements, sedOPR ) {
        shift := select( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = sedOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1" ); 
        if ( not isnull( shift ) ) {
          endDate     := guard( maxselect( macroPlan, ShiftPattern.ShiftDayTime, tempSDT, tempSDT.ShiftPattern().Name() = shift.Shift(), tempSDT.Sequence() ).EndDateTIme().Format( "H:m" ), "" );
          endDateCell := sedOPR.OfflinePlanCell( relnew, Value := endDate );
          endDateCell.OfflinePlanColumn( relset, opc );
        }
      }
    }
    
    // 补全时间列
    indexDate := macroPlan.StartOfPlanning().Date();
    endDate   := Date::Construct( indexDate.Year(), 12, 31 );
    while ( indexDate <= endDate ) {
      opc := select( opt, OfflinePlanColumn, tempOPC, tempOPC.ColumnDate() = indexDate );
      if ( isnull( opc ) ) {
        opc := opt.OfflinePlanColumn( relnew, ColumnDate := indexDate );
      }
      indexDate := indexDate + 1;
    }
    
    // 补全空格子
    traverse ( opt, OfflinePlanRow, opr ) {
      traverse ( opt, OfflinePlanColumn, opc ) {
        cell := select( opr, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanColumn() = opc );
        if ( isnull( cell ) ) {
          cell := opr.OfflinePlanCell( relnew, Value := "" );
          cell.OfflinePlanColumn( relset, opc );
        }
      }
    }
    
    Transaction::Transaction().Propagate( attribute( OfflinePlanCell, Quantity ) );
    Transaction::Transaction().PropagateAll();
    
    // 设置生产顺序
    productionLines := selectuniquevalues( opt, OfflinePlanRow, tempOPR, true, tempOPR.ProductionLine() );
    traverse ( productionLines, Elements, pl ) {
      indexColumn    := select( opt, OfflinePlanColumn, tempOPC, tempOPC.ColumnDate() = macroPlan.StartOfPlanning().Date() );
      previousColumn := indexColumn.PreviousColumn();
      nextColumn     := indexColumn.NextColumn();
      
      while ( not isnull( indexColumn.NextColumn() ) 
    //          and indexColumn.ColumnDate() <= Date::Construct( 2020, 4, 1 ) // 测试实际场景时可以过滤
             ) {
        productionSerialNumber := 1;
        opcs                   := selectsortedset( indexColumn, OfflinePlanCell, tempOPC, tempOPC.FindType( "2", pl ), tempOPC.InventoryWeight() );
        initialSize            := opcs.Size();
        info( "计划开始时间:", macroPlan.StartOfPlanning().Date().Format( "Y-M2-D2" ), "    索引时间:", indexDate.Format( "Y-M2-D2" ), "    个数:", opcs.Size() );
        if ( opcs.Size() > 0 ) { 
          // 判定1
          previousOPC := maxselect( previousColumn, OfflinePlanCell, tempOPC, tempOPC.FindType( "2", pl ), tempOPC.ProductionSerialNumber() );
          if ( isnull( previousOPC ) or indexColumn.ColumnDate() = macroPlan.StartOfPlanning().Date() ) {
            opc := opcs.Element( 0 );
            opc.Value( "#" + productionSerialNumber.Format( "N(LPad0(2))" ) );
            opc.ProductionSerialNumber( productionSerialNumber );
            productionSerialNumber++;
            opcs.Remove( opc );
          } else {
            opc := select( opcs, Elements, tempOPC, tempOPC.OfflinePlanRow().ProductID() = previousOPC.OfflinePlanRow().ProductID() );
            if ( not isnull( opc ) ) {
              opc.Value( "#" + productionSerialNumber.Format( "N(LPad0(2))" ) );
              opc.ProductionSerialNumber( productionSerialNumber );
              productionSerialNumber++;
              opcs.Remove( opc );
            }
          }
          
          // 判定2
          nextOPCs := selectset( opcs, Elements, tempOPC,
                                 exists( nextColumn, OfflinePlanCell, nextOPC, nextOPC.FindType( "2", pl ) and nextOPC.OfflinePlanRow().ProductID() = tempOPC.OfflinePlanRow().ProductID() ) );
          if ( nextOPCs.Size() = 1 ) {
            opc := nextOPCs.Element( 0 );
            opc.Value( "#" + initialSize.Format( "N(LPad0(2))" ) );
            opc.ProductionSerialNumber( initialSize );
            opcs.Remove( opc );
          }
          
          // 判定3
          traverse ( opcs, Elements, opc ) {
            opc.Value( "#" + productionSerialNumber.Format( "N(LPad0(2))" ) );
            opc.ProductionSerialNumber( productionSerialNumber );
            productionSerialNumber++;
            opcs.Remove( opc );
          }
        }
        
        indexColumn    := indexColumn.NextColumn();
        previousColumn := indexColumn.PreviousColumn();
        nextColumn     := indexColumn.NextColumn();
      }
    }
  *]
}