admin
2025-01-22 7e31442f0e9b07764e9c6a9680d3d4aeba5fe1de
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
Quintiq file version 2.0
#parent: #root
StaticMethod CreateOrUpdateForUnitPeriodQuantity (
  UnitPeriodQuantity unitperiodquantity,
  Boolean isbatcheditcapacity,
  String timeunit,
  Real mincapacity,
  Real maxcapacity,
  Boolean isbatcheditmaxloadpercentage,
  Real maxloadpercentage,
  Boolean isbatcheditnrofunitsopen,
  Number nrofunitsopen,
  Boolean isthisperiodonwards
)
{
  Description: "Create or update the unit capacity when we want only the particular unit period quantity user's value ( get from unit capacity ) change."
  TextBody:
  [*
    // soh yee Feb-20-2013 (modified)
    unit := unitperiodquantity.Unit();
    defaultmaxcapacity := unit.MacroPlan().GlobalParameters_MP().DefaultMaxCapacityPerDayForUnit();
    unitcapacity := unitperiodquantity.UnitCapacity();
    
    // If the batch edit checkbox in UI is unchecked, we get the data from the current unit capacity.
    // Didn't use guard for more readability.
    if( not isbatcheditcapacity )
    {
      timeunit := unitperiodquantity.Period_MP().PeriodSpecification_MP().TimeUnit();
      mincapacity := 0.0;
      maxcapacity := defaultmaxcapacity;
    
      if( unitperiodquantity.HasUnitCapacity() )
      {
        timeunit := unitcapacity.TimeUnit();
        mincapacity := unitcapacity.MinCapacity();
        maxcapacity := unitcapacity.MaxCapacity();
      }
    }
    
    if( not isbatcheditmaxloadpercentage )
    {
      maxloadpercentage := unitperiodquantity.MaximumLoadPercentage();
    
      if( unitperiodquantity.HasUnitCapacity() )
      {
        maxloadpercentage := unitcapacity.MaximumLoadPercentage();
      }
    }
    
    if( not isbatcheditnrofunitsopen )
    {
      nrofunitsopen := unitperiodquantity.NrOfOpen();
    
      if( unitperiodquantity.HasUnitCapacity() )
      {
        nrofunitsopen := unitcapacity.NrOfUnitsOpen();
      }
    }
    
    /*
    Case1: all unit period quantitys are referring to Jan, 1(nrofunitsopen), 0(nrofunitstempclose).
    Unit period quantity      Unit capacity
      Jan                     Jan, 1, 0
      Feb
      Mar
      Apr
    
    Case2: when user open 1 more unit on Mar, (a) and (b) are created.
    Unit period quantity      Unit capacity
      Jan                     Jan, 1, 0
      Feb                     Mar, 2, 0 (a)
      Mar                     Apr, 1, 0 (b)
      Apr
    
    
    Case3: when user open 1 more unit starting from Apr, (b) is updated.
    Unit period quantity      Unit capacity
      Jan                     Jan, 1,0
      Feb                     Mar, 2,0 (a)
      Mar                     Apr, 2,0 (b)
      Apr
    
    Special case: When the scenario have parallel periods, for example Weeks and Days.
    Unit period quantity      Unit capacity
    Week 1 (isbase)           Week 1
    Week 2 (isbase)           Week 2
    Week 3 (not base)         Day 1, Day 2, Day 3, Day 5, Day 6, Day 7
    Week 4 (not base)         Day 1, Day 2, Day 3, Day 5, Day 6, Day 7
    */
    
    nextupq := unitperiodquantity.Next().astype( UnitPeriodQuantity );
    nextunitcapacity := guard( nextupq.UnitCapacity(), null( UnitCapacity ) );
    
    // Get all period dimension children's unit capacity, for handling special case and when isthisperiodonwads is true
    unitcapacitys := selectset( unit, UnitCapacity, uc,
                                uc.Start() >= unitperiodquantity.Start()
                                and ( uc.Start() < unitperiodquantity.Period_MP().End() // Ignore the end if isthisperiodonwards
                                      or isthisperiodonwards ) );
    
    // To handle special case and when isthisperiodonwads is true
    if( unitcapacitys.Size() > 0
        and not isnull( nextupq ) )
    {
      lastchilduc := null( UnitCapacity );
    
      // If have next uc, we want to shift the last uc from the childuc as next period uc
      if( not isthisperiodonwards )
      {
        // Shift the last uc of the child period to next period
        lastchilduc := maxselect( unit, UnitCapacity, uc, unitperiodquantity.End() >= uc.Start(), uc.Start() );
    
        if( UnitCapacity::IsPrimaryKeysUnique( unit, nextupq.Start(), null( UnitCapacity ) ) )
        {
          // Keep all value except the start, to handle period > day where it have uc start in the middle of the period
          // We will shift the last uc to next period
          lastchilduc.Update( lastchilduc.Unit(),
                              nextupq.Start(),
                              lastchilduc.TimeUnit(),
                              lastchilduc.MinCapacity(),
                              lastchilduc.MaxCapacity(),
                              lastchilduc.MaximumLoadPercentage(),
                              lastchilduc.NrOfUnitsOpen(),
                              false );
        }
      }
    
      // Delete all uc except the shifted one (also for handle isthisperiodonwads for week 3, 4 Day 1~7 for the given example)
      traverse( unitcapacitys, Elements, e,
                e <> unitcapacity
                and e <> lastchilduc )
      {
        e.Delete();
      }
    
      // Propogate the relation to unit period quantity.
      // This is needed for the following checking.
      Transaction::Transaction().Propagate();
    }
    
    if( not isthisperiodonwards
        and not isnull( nextupq )
        and nextunitcapacity = unitcapacity
        and UnitCapacity::IsPrimaryKeysUnique( unit, nextupq.Start(), null( UnitCapacity ) ) )
    {
      // Case2: creating (b)
      nexttimeunit := Translations::MP_GlobalParameters_Day(); // Default to capacity in global paramter which is in day
      nextmincapacity := unit.MacroPlan().GlobalParameters_MP().DefaultMinCapacityPerDayForUnit();
      nextmaxcapacity := unit.MacroPlan().GlobalParameters_MP().DefaultMaxCapacityPerDayForUnit();
      nextmaxloadpercentage := unit.MacroPlan().GlobalParameters_MP().DefaultMaxLoadPercentage();
      nextnrofunitsopen := nextupq.NrOfOpen();
    
      if( unitperiodquantity.HasUnitCapacity() )
      {
        nexttimeunit := unitcapacity.TimeUnit();
        nextmincapacity := unitcapacity.MinCapacity();
        nextmaxcapacity := unitcapacity.MaxCapacity();
        nextmaxloadpercentage := unitcapacity.MaximumLoadPercentage();
        nextnrofunitsopen := unitcapacity.NrOfUnitsOpen();
      }
    
      UnitCapacity::Create( unit,
                            nextupq.Start(),
                            nexttimeunit,
                            nextmincapacity,
                            nextmaxcapacity,
                            nextmaxloadpercentage,
                            nextnrofunitsopen,
                            false );
    
      // Propogate the relation to unit period quantity.
      // This is needed for the following checking.
      Transaction::Transaction().Propagate();
    }
    
    // Create a new unit capacity for that particular unit period quantity if it does not bind to any unit capacity, or if it already has a unit capacity,
    // the related unit capacity doesn't have the same start as the unit period quantity.
    if( not unitperiodquantity.HasUnitCapacity()
        or UnitCapacity::IsPrimaryKeysUnique( unit, unitperiodquantity.Start(), null( UnitCapacity ) ) )
    {
      // Case2: creating (a)
      UnitCapacity::Create( unit,
                            unitperiodquantity.Start(),
                            timeunit,
                            mincapacity,
                            maxcapacity,
                            maxloadpercentage,
                            nrofunitsopen,
                            false );
    }
    
    else
    {
      // Case3, (b) is updated.
      // The to-be created unit capacity has the same primary keys with existing data. Therefore, we update it instead of creating a new data to avoid duplication.
      unitcapacity.Update( unit,
                           unitcapacity.Start(),
                           timeunit,
                           mincapacity,
                           maxcapacity,
                           maxloadpercentage,
                           nrofunitsopen,
                           false );
    }
  *]
}