Make date field wider to accommodate 10 digits properly.
[capital-apms-progress.git] / process / genopex.p
blob0a34349cd17df85d938dd01fb89d087663079aed
1 &ANALYZE-SUSPEND _VERSION-NUMBER UIB_v8r12
2 &ANALYZE-RESUME
3 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _DEFINITIONS Procedure
4 /*--------------------------------------------------------------------------------------------
5 File : process/genRECV.p
6 Purpose : Generate forecast cash flows for opex recoveries
7 Author(s) : Andrew McMillan
8 ------------------------------------------------------------------------*/
9 DEF INPUT PARAMETER process-options AS CHAR NO-UNDO.
10 DEF VAR scenario-code LIKE Scenario.ScenarioCode NO-UNDO.
11 DEF VAR debug-mode AS LOGI NO-UNDO INITIAL No.
12 RUN parse-options.
14 {inc/ofc-this.i}
15 {inc/ofc-set.i "RentCharge-Type" "rent-charge-type" "ERROR"}
16 {inc/ofc-set.i "AcctGroup-Opex" "recoverable-groups" "ERROR"}
18 ON WRITE OF CashFlow DO:
19 IF NEW CashFlow THEN DO:
20 DEF BUFFER LastCashFlow FOR CashFlow.
21 FIND LAST LastCashFlow WHERE
22 LastCashFlow.ScenarioCode = CashFlow.ScenarioCode AND
23 LastCashFlow.EntityType = CashFlow.EntityType AND
24 LastCashFlow.EntityCode = CashFlow.EntityCode AND
25 LastCashFlow.AccountCode = CashFlow.AccountCode AND
26 LastCashFlow.CashFlowType = CashFlow.CashFlowType
27 NO-LOCK NO-ERROR.
28 ASSIGN CashFlow.Sequence = IF AVAILABLE LastCashFlow THEN
29 LastCashFlow.Sequence + 1 ELSE 1.
30 END.
31 END.
33 /* Selection variables */
34 DEF VAR entity-list AS CHAR NO-UNDO.
35 DEF VAR entity-list-type AS CHAR NO-UNDO.
36 DEF VAR entity-list-by AS CHAR NO-UNDO.
37 DEF VAR all-entities AS LOGI NO-UNDO.
39 DEF VAR service-types AS CHAR NO-UNDO.
40 DEF VAR forecast-start AS DATE NO-UNDO.
41 DEF VAR forecast-end AS DATE NO-UNDO.
42 DEF VAR washup-cycle AS DATE NO-UNDO.
44 /* parameters affecting generation of RECV */
45 DEF VAR profiled AS LOGI NO-UNDO INITIAL No.
46 DEF VAR recovered-offset AS DEC NO-UNDO INITIAL 0.2 .
48 DEF TEMP-TABLE PX NO-UNDO
49 FIELD ac LIKE ChartOfAccount.AccountCode
50 FIELD mc LIKE Month.MonthCode
51 FIELD amt AS DEC
52 FIELD d-start AS DATE
53 FIELD d-end AS DATE
54 INDEX x1 IS UNIQUE PRIMARY ac mc.
56 DEF WORK-TABLE RX NO-UNDO
57 FIELD mc LIKE Month.MonthCode
58 FIELD ac LIKE ChartOfAccount.AccountCode
59 FIELD amt AS DEC
60 FIELD d-start AS DATE
61 FIELD d-end AS DATE
62 FIELD percent AS DEC
63 FIELD r-desc AS CHAR
64 FIELD relate AS CHAR.
66 /* _UIB-CODE-BLOCK-END */
67 &ANALYZE-RESUME
70 &ANALYZE-SUSPEND _UIB-PREPROCESSOR-BLOCK
72 /* ******************** Preprocessor Definitions ******************** */
74 &Scoped-define PROCEDURE-TYPE Procedure
78 /* _UIB-PREPROCESSOR-BLOCK-END */
79 &ANALYZE-RESUME
82 /* ************************ Function Prototypes ********************** */
84 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD check-manual-flow Procedure
85 FUNCTION check-manual-flow RETURNS LOGICAL
86 ( INPUT man-type AS CHAR, INPUT chg-type AS CHAR, INPUT-OUTPUT d-1 AS DATE, INPUT-OUTPUT d-n AS DATE ) FORWARD.
88 /* _UIB-CODE-BLOCK-END */
89 &ANALYZE-RESUME
91 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD get-parameter Procedure
92 FUNCTION get-parameter RETURNS CHARACTER
93 ( INPUT parameter-name AS CHAR ) FORWARD.
95 /* _UIB-CODE-BLOCK-END */
96 &ANALYZE-RESUME
98 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD id-code Procedure
99 FUNCTION id-code RETURNS CHARACTER
100 ( INPUT type AS CHAR ) FORWARD.
102 /* _UIB-CODE-BLOCK-END */
103 &ANALYZE-RESUME
105 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD include-property Procedure
106 FUNCTION include-property RETURNS LOGICAL
107 ( /* parameter-definitions */ ) FORWARD.
109 /* _UIB-CODE-BLOCK-END */
110 &ANALYZE-RESUME
112 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD is-recoverable Procedure
113 FUNCTION is-recoverable RETURNS LOGICAL
114 ( INPUT ac AS DEC ) FORWARD.
116 /* _UIB-CODE-BLOCK-END */
117 &ANALYZE-RESUME
120 /* *********************** Procedure Settings ************************ */
122 &ANALYZE-SUSPEND _PROCEDURE-SETTINGS
123 /* Settings for THIS-PROCEDURE
124 Type: Procedure
125 Allow:
126 Frames: 0
127 Add Fields to: Neither
128 Other Settings: CODE-ONLY COMPILE
130 &ANALYZE-RESUME _END-PROCEDURE-SETTINGS
132 /* ************************* Create Window ************************** */
134 &ANALYZE-SUSPEND _CREATE-WINDOW
135 /* DESIGN Window definition (used by the UIB)
136 CREATE WINDOW Procedure ASSIGN
137 HEIGHT = .33
138 WIDTH = 40.
139 /* END WINDOW DEFINITION */
141 &ANALYZE-RESUME
145 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _INCLUDED-LIB Procedure
146 /* ************************* Included-Libraries *********************** */
148 {inc/method/m-debug.i}
149 {inc/cashflow.i}
151 /* _UIB-CODE-BLOCK-END */
152 &ANALYZE-RESUME
156 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _MAIN-BLOCK Procedure
159 /* *************************** Main Block *************************** */
160 &SCOP KEEP-DEBUG-MESSAGES KEEP-MESSAGES
161 {&DEBUG-BEGIN}
163 FIND Scenario WHERE Scenario.ScenarioCode = scenario-code NO-LOCK.
165 debug-event("Starting").
166 RUN get-parameters.
167 RUN delete-current-cash-flows.
168 RUN generate-recoveries.
170 debug-event("Finished").
171 RUN debug-end.
173 MESSAGE "Forecast Recovery Regeneration Complete" VIEW-AS ALERT-BOX INFORMATION
174 TITLE "Completed".
176 {&DEBUG-END}
178 /* _UIB-CODE-BLOCK-END */
179 &ANALYZE-RESUME
182 /* ********************** Internal Procedures *********************** */
184 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE build-expense-table Procedure
185 PROCEDURE build-expense-table :
186 /*------------------------------------------------------------------------------
187 Purpose: Build the PX table of expenses for this property
188 ------------------------------------------------------------------------------*/
189 /* clear any existing records */
190 FOR EACH PX: DELETE PX. END.
192 DEF VAR i AS INT NO-UNDO.
193 DEF VAR n AS INT NO-UNDO.
194 DEF VAR yy AS INT NO-UNDO.
195 DEF VAR mm AS INT NO-UNDO.
197 DEF VAR hdrs AS CHAR NO-UNDO.
198 DEF VAR flows AS CHAR NO-UNDO.
199 DEF VAR hdr AS CHAR NO-UNDO.
200 DEF VAR n-mths-per AS INT NO-UNDO.
201 DEF VAR flow-period-start AS DATE NO-UNDO.
203 /* Clear previous ones */
204 debug-event( "Clearing expense table" ).
205 FOR EACH PX: DELETE PX. END.
206 debug-event( "Building expense table" ).
208 FOR EACH CashFlow OF Scenario WHERE CashFlow.EntityType = "P"
209 AND CashFlow.EntityCode = Property.PropertyCode:
210 IF LOOKUP( CashFlow.CashFlowType, "RENT,MRNT,RECV,MREC") > 0 THEN NEXT.
211 IF NOT is-recoverable(CashFlow.AccountCode) THEN NEXT.
213 n-mths-per = get-freq-months( CashFlow.FrequencyCode ).
214 IF n-mths-per > 1 THEN DO:
215 /* this ensures that we have a blank cashflow to cover the whole period */
216 flow-period-start = add-months( start-of-bucket( ENTRY(1,hdrs)), 1 - n-mths-per ).
217 IF flow-period-start < forecast-start THEN flow-period-start = forecast-start.
218 FIND Month WHERE Month.StartDate = flow-period-start NO-LOCK NO-ERROR.
219 IF AVAILABLE(Month) THEN DO:
220 FIND FIRST PX WHERE PX.ac = CashFlow.AccountCode
221 AND PX.mc = Month.MonthCode NO-ERROR.
222 IF NOT AVAILABLE(PX) THEN DO:
223 CREATE PX.
224 PX.ac = CashFlow.AccountCode.
225 PX.mc = Month.MonthCode.
226 PX.amt = 0.
227 PX.d-start = Month.StartDate.
228 PX.d-end = Month.EndDate.
229 END.
230 END.
231 END.
233 IF n-mths-per > 1 AND NOT(profiled) THEN
234 RUN split-cash-flow( forecast-start, forecast-end, "MNTH",
235 CashFlow.StartDate, CashFlow.EndDate, "MNTH",
236 (CashFlow.Amount / n-mths-per), No, OUTPUT hdrs, OUTPUT flows ).
237 ELSE
238 RUN split-cash-flow( forecast-start, forecast-end, "MNTH",
239 CashFlow.StartDate, CashFlow.EndDate, CashFlow.FrequencyCode,
240 CashFlow.Amount, No, OUTPUT hdrs, OUTPUT flows ).
242 n = NUM-ENTRIES(hdrs).
243 DO i = 1 TO n:
244 hdr = ENTRY(i,hdrs).
245 FIND Month WHERE Month.StartDate = start-of-bucket(hdr) NO-LOCK NO-ERROR.
246 IF NOT AVAILABLE(Month) THEN DO:
247 debug-event( "Can't find month record for '" + hdr + "'").
248 NEXT.
249 END.
251 FIND FIRST PX WHERE PX.ac = CashFlow.AccountCode
252 AND PX.mc = Month.MonthCode NO-ERROR.
253 IF NOT AVAILABLE(PX) THEN DO:
254 CREATE PX.
255 PX.ac = CashFlow.AccountCode.
256 PX.mc = Month.MonthCode.
257 PX.amt = 0.
258 PX.d-start = Month.StartDate.
259 PX.d-end = Month.EndDate.
260 END.
261 PX.amt = PX.amt + DEC(ENTRY(i,flows)).
262 END.
263 END.
265 DEF VAR ths-ac AS DEC NO-UNDO.
266 DEF VAR first-mc AS INT NO-UNDO.
267 DEF VAR last-mc AS INT NO-UNDO.
269 FIND LAST Month WHERE Month.StartDate <= forecast-start NO-LOCK.
270 first-mc = Month.MonthCode.
271 FIND LAST Month WHERE Month.StartDate < forecast-end NO-LOCK.
272 last-mc = Month.MonthCode.
274 FIND FIRST PX NO-ERROR.
275 DO WHILE AVAILABLE(PX):
276 ths-ac = PX.ac.
277 FOR EACH Month WHERE Month.MonthCode >= PX.mc AND Month.MonthCode <= last-mc NO-LOCK:
278 IF NOT CAN-FIND(PX WHERE PX.ac = ths-ac AND PX.mc = Month.MonthCode) THEN DO:
279 CREATE PX.
280 PX.ac = ths-ac.
281 PX.mc = Month.MonthCode.
282 PX.amt = 0.
283 PX.d-start = Month.StartDate.
284 PX.d-end = Month.EndDate.
285 END.
286 END.
287 FIND FIRST PX WHERE PX.ac > ths-ac NO-ERROR.
288 END.
290 END PROCEDURE.
292 /* _UIB-CODE-BLOCK-END */
293 &ANALYZE-RESUME
296 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE clear-rx-records Procedure
297 PROCEDURE clear-rx-records :
298 /*------------------------------------------------------------------------------
299 Purpose:
300 ------------------------------------------------------------------------------*/
301 FOR EACH RX: DELETE RX. END.
303 END PROCEDURE.
305 /* _UIB-CODE-BLOCK-END */
306 &ANALYZE-RESUME
309 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE create-flow Procedure
310 PROCEDURE create-flow :
311 /*------------------------------------------------------------------------------
312 Purpose:
313 ------------------------------------------------------------------------------*/
314 DEF INPUT PARAMETER cf-type AS CHAR NO-UNDO.
315 DEF INPUT PARAMETER chg-type AS CHAR NO-UNDO.
316 DEF INPUT PARAMETER account AS DEC NO-UNDO.
317 DEF INPUT PARAMETER start-date AS DATE NO-UNDO.
318 DEF INPUT PARAMETER end-date AS DATE NO-UNDO.
319 DEF INPUT PARAMETER frequency-code AS CHAR NO-UNDO.
320 DEF INPUT PARAMETER amount AS DEC NO-UNDO.
321 DEF INPUT PARAMETER related AS CHAR NO-UNDO.
322 DEF INPUT PARAMETER description AS CHAR NO-UNDO.
324 DEF VAR manual-flow-type AS CHAR NO-UNDO.
326 IF start-date > forecast-end THEN RETURN.
328 IF cf-type = "RECV" THEN manual-flow-type = "MREC".
329 ELSE IF cf-type = "SCL" THEN manual-flow-type = "MSCL".
330 ELSE IF cf-type = "RENT" THEN manual-flow-type = "MRNT".
331 ELSE manual-flow-type = "".
333 IF manual-flow-type <> "" THEN DO:
334 IF NOT check-manual-flow( manual-flow-type, chg-type,
335 INPUT-OUTPUT start-date, INPUT-OUTPUT end-date ) THEN RETURN.
336 END.
339 CREATE CashFlow.
340 ASSIGN CashFlow.ScenarioCode = Scenario.ScenarioCode
341 CashFlow.EntityType = "P"
342 CashFlow.EntityCode = Property.PropertyCode
343 CashFlow.RelatedKey = related
344 CashFlow.CashFlowType = cf-type
345 CashFlow.CFChangeType = chg-type
346 CashFlow.AccountCode = account
347 CashFlow.StartDate = start-date
348 CashFlow.EndDate = (IF end-date >= forecast-end THEN ? ELSE end-date)
349 CashFlow.FrequencyCode = frequency-code
350 CashFlow.Amount = amount
351 CashFlow.Description = description.
353 debug-event( "Created cashflow " + STRING( CashFlow.StartDate, "99/99/9999") + " to " + STRING( end-date, "99/99/9999" ) + ", " + STRING(amount) + ", related: " + related).
355 END PROCEDURE.
357 /* _UIB-CODE-BLOCK-END */
358 &ANALYZE-RESUME
361 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE delete-current-cash-flows Procedure
362 PROCEDURE delete-current-cash-flows :
363 /*------------------------------------------------------------------------------
364 Purpose:
365 Parameters: <none>
366 Notes:
367 ------------------------------------------------------------------------------*/
369 debug-event("Deleting current RECV cash flows").
370 FOR EACH CashFlow OF Scenario WHERE CashFlow.ScenarioCode = scenario-code
371 AND CashFlow.CashFlowType = "RECV":
372 DELETE CashFlow.
373 END.
375 END PROCEDURE.
377 /* _UIB-CODE-BLOCK-END */
378 &ANALYZE-RESUME
381 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE each-tenancy-lease Procedure
382 PROCEDURE each-tenancy-lease :
383 /*------------------------------------------------------------------------------
384 Purpose:
385 Parameters: <none>
386 Notes:
387 ------------------------------------------------------------------------------*/
388 DEF VAR rental-freq AS CHAR NO-UNDO.
389 DEF VAR rental-fract AS DEC NO-UNDO.
390 DEF VAR monthly-lease AS LOGI NO-UNDO.
391 DEF VAR review-list AS CHAR NO-UNDO.
393 rental-freq = IF CAN-FIND( FIRST FrequencyType WHERE
394 FrequencyType.FrequencyCode = TenancyLease.PaymentFrequency ) THEN
395 TenancyLease.PaymentFrequency ELSE "MNTH".
396 RUN process/calcfreq.p ( rental-freq, OUTPUT rental-fract ).
397 monthly-lease = TenancyLease.LeaseEndDate = ? OR TenancyLease.LeaseEndDate < TODAY.
399 review-list = "".
400 FOR EACH RentReview NO-LOCK OF TenancyLease WHERE ReviewStatus <> "DONE"
401 AND RentReview.DateDue >= forecast-start
402 AND RentReview.DateDue <= forecast-end:
403 review-list = review-list + STRING( RentReview.DateDue, "99/99/9999") + ",".
404 END.
406 FOR EACH RentalSpace NO-LOCK OF TenancyLease:
407 RUN each-rental-space( rental-freq, rental-fract, monthly-lease,
408 TenancyLease.LeaseStartDate, TenancyLease.LeaseEndDate, review-list ).
409 END.
412 END PROCEDURE.
414 /* _UIB-CODE-BLOCK-END */
415 &ANALYZE-RESUME
418 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE generate-recoveries Procedure
419 PROCEDURE generate-recoveries :
420 /*------------------------------------------------------------------------------
421 Purpose:
422 Parameters: <none>
423 Notes:
424 ------------------------------------------------------------------------------*/
426 FOR EACH Property NO-LOCK:
427 IF NOT include-property() THEN NEXT.
429 debug-event( "Opex recoveries for P" + STRING(Property.PropertyCode) + " - " + Property.Name ).
430 RUN build-expense-table.
431 RUN property-cash-flows.
432 END.
434 END PROCEDURE.
436 /* _UIB-CODE-BLOCK-END */
437 &ANALYZE-RESUME
440 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE get-parameters Procedure
441 PROCEDURE get-parameters :
442 /*------------------------------------------------------------------------------
443 Purpose:
444 ------------------------------------------------------------------------------*/
445 DEF VAR parm AS CHAR NO-UNDO.
447 entity-list = get-parameter( "In-Entities" ).
448 entity-list-type = ENTRY( 1, entity-list).
449 entity-list-by = ENTRY( 2, entity-list).
450 entity-list = SUBSTRING( entity-list, LENGTH(entity-list-by) + 3).
451 all-entities = entity-list = "ALL".
453 forecast-start = DATE( get-parameter( "Forecast-Start" ) ).
454 IF forecast-start = ? THEN forecast-start = DATE( 1, 1, YEAR(TODAY)).
455 forecast-end = DATE( get-parameter( "Forecast-End" ) ).
456 IF forecast-end = ? THEN forecast-end = add-date( TODAY, 11, 0, 0 ).
458 washup-cycle = DATE( get-parameter( "Washup-Cycle" ) ).
459 IF washup-cycle = ? THEN washup-cycle = DATE( 1, 1, YEAR(TODAY) ) - 1.
460 debug-event( "Washup cycle date is: " + STRING( washup-cycle, "99/99/9999") ).
462 profiled = (get-parameter( "Profile-Recoveries" ) = "Yes").
463 parm = get-parameter( "Recovery-Offset" ).
464 IF parm <> "" THEN
465 recovered-offset = DEC( parm ).
466 ELSE
467 recovered-offset = 0.2 .
469 END PROCEDURE.
471 /* _UIB-CODE-BLOCK-END */
472 &ANALYZE-RESUME
475 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE make-rx-records Procedure
476 PROCEDURE make-rx-records :
477 /*------------------------------------------------------------------------------
478 Purpose:
479 ------------------------------------------------------------------------------*/
480 DEF INPUT PARAMETER d-1 AS DATE NO-UNDO.
481 DEF INPUT PARAMETER d-n AS DATE NO-UNDO.
482 DEF INPUT PARAMETER summarise AS LOGI NO-UNDO.
483 DEF INPUT PARAMETER relate AS CHAR NO-UNDO.
485 DEF VAR part-month AS DEC NO-UNDO.
486 DEF VAR m-1 AS INT NO-UNDO.
487 DEF VAR m-n AS INT NO-UNDO.
489 IF d-1 < forecast-start OR d-1 = ? THEN d-1 = forecast-start.
490 IF d-n > forecast-end OR d-n = ? THEN d-n = forecast-end.
491 debug-event( "Making RX records from " + STRING( d-1, "99/99/9999")
492 + " to " + STRING( d-n, "99/99/9999")
493 + ", All=" + STRING( summarise )
494 + ", Relate=" + relate ).
496 IF summarise AND RentalSpace.OutgoingsPercentage <= 0 THEN DO:
497 debug-event( "No percentage on rental space: " + relate ).
498 RETURN.
499 END.
501 FIND LAST Month WHERE Month.StartDate <= d-1 NO-LOCK NO-ERROR.
502 IF NOT AVAILABLE(Month) THEN DO:
503 debug-event( "Couldn't find month for " + STRING( d-1, "99/99/9999") ).
504 RETURN.
505 END.
506 m-1 = Month.MonthCode.
507 FIND FIRST Month WHERE Month.EndDate >= d-n NO-LOCK NO-ERROR.
508 IF NOT AVAILABLE(Month) THEN DO:
509 debug-event( "Couldn't find month for " + STRING( d-n, "99/99/9999") ).
510 RETURN.
511 END.
512 m-n = Month.MonthCode.
514 IF summarise THEN DO:
515 FOR EACH PX WHERE PX.mc >= m-1 AND PX.mc <= m-n :
516 IF d-n < PX.d-end OR d-1 > PX.d-start THEN
517 part-month = (MIN( PX.d-end, d-n) - MAX(PX.d-start, d-1)) / (PX.d-end - PX.d-start) .
518 ELSE
519 part-month = 1.0 .
521 CREATE RX.
522 BUFFER-COPY PX TO RX ASSIGN
523 RX.percent = RentalSpace.OutGoingsPercentage * part-month
524 RX.amt = - (PX.amt * (RX.percent / 100))
525 RX.relate = relate
526 RX.r-desc = "Recover " + TRIM( STRING( RX.percent, "->,>>9.99"))
527 + "% of " + TRIM( STRING( PX.amt, "->>,>>>,>>9.99")).
528 END.
529 END.
530 ELSE DO:
531 FOR EACH TenancyOutgoing NO-LOCK OF TenancyLease,
532 EACH PX WHERE PX.ac = TenancyOutgoing.AccountCode
533 AND PX.mc >= m-1 AND PX.mc <= m-n:
534 IF d-n < PX.d-end OR d-1 > PX.d-start THEN
535 part-month = (MIN( PX.d-end, d-n) - MAX(PX.d-start, d-1)) / (PX.d-end - PX.d-start) .
536 ELSE
537 part-month = 1.0 .
539 CREATE RX.
540 BUFFER-COPY PX TO RX ASSIGN
541 RX.percent = TenancyOutgoing.Percentage * part-month
542 RX.amt = - (PX.amt * (RX.percent / 100))
543 RX.relate = relate
544 RX.r-desc = "Recover " + TRIM( STRING( RX.percent, "->,>>9.99"))
545 + "% of " + TRIM( STRING( PX.amt, "->>,>>>,>>9.99")).
546 END.
547 END.
549 END PROCEDURE.
551 /* _UIB-CODE-BLOCK-END */
552 &ANALYZE-RESUME
555 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE old-property-cash-flows Procedure
556 PROCEDURE old-property-cash-flows :
557 /*------------------------------------------------------------------------------
558 Purpose:
559 ------------------------------------------------------------------------------*/
560 DEF BUFFER RentFlow FOR CashFlow.
561 DEF BUFFER OtherFlow FOR CashFlow.
563 DEF VAR part-month AS DEC NO-UNDO.
564 DEF VAR rsp-code AS INT NO-UNDO.
565 DEF VAR exclude-lease AS LOGICAL NO-UNDO.
566 DEF VAR lease-list AS CHAR NO-UNDO.
567 DEF VAR d-1 AS DATE NO-UNDO.
568 DEF VAR d-n AS DATE NO-UNDO.
569 DEF VAR last-rsp-code AS INT NO-UNDO INITIAL ?.
571 debug-event( "Processing rental cash flows of property" ).
572 FOR EACH RentFlow NO-LOCK OF Scenario WHERE RentFlow.EntityType = "P"
573 AND RentFlow.EntityCode = Property.PropertyCode
574 AND (RentFlow.CashFlowType = "RENT" OR RentFlow.CashFlowType = "MRNT")
575 AND (RentFlow.CFChangeType = "N" OR RentFlow.CFChangeType = "R")
576 BY RentFlow.RelatedKey:
577 debug-event( "Looking at rental flow for " + RentFlow.RelatedKey ).
578 rsp-code = INT(ENTRY( 8, RentFlow.RelatedKey)).
579 IF rsp-code <> last-rsp-code THEN DO:
580 IF last-rsp-code <> ? THEN DO:
581 /* create flows for the RX amounts */
582 IF profiled THEN RUN profiled-flows. ELSE RUN smoothed-flows.
583 END.
584 last-rsp-code = rsp-code.
585 RUN clear-rx-records.
586 END.
587 FIND RentalSpace NO-LOCK OF Property WHERE RentalSpace.RentalSpaceCode = rsp-code NO-ERROR.
588 IF NOT AVAILABLE(RentalSpace) THEN DO:
589 debug-event("Rental space '" + RentFlow.RelatedKey + "' not available!").
590 NEXT.
591 END.
593 exclude-lease = RentalSpace.AreaStatus = "V".
594 IF NOT exclude-lease THEN DO:
595 /* need lease-list to include date identifier */
596 IF LOOKUP( STRING(RentalSpace.TenancyLeaseCode) + "-" + STRING(RentFlow.StartDate),
597 lease-list ) > 0 THEN DO:
598 debug-event( "Skipping - tenancylease " + STRING(RentalSpace.TenancyLeaseCode)
599 + ", starting on " + STRING(RentFlow.StartDate) + " already processed").
600 exclude-lease = Yes.
601 END.
602 ELSE DO:
603 lease-list = lease-list + STRING(RentalSpace.TenancyLeaseCode) + "-" + STRING(RentFlow.StartDate) + ",".
604 END.
605 END.
606 IF NOT exclude-lease THEN DO:
607 FIND TenancyLease NO-LOCK OF RentalSpace NO-ERROR.
608 IF NOT AVAILABLE(TenancyLease) THEN DO:
609 debug-event( "Skipping - no tenancylease found for Rental space '" + RentFlow.RelatedKey + "'").
610 exclude-lease = Yes.
611 END.
612 ELSE IF NOT CAN-FIND(FIRST TenancyOutGoing OF TenancyLease WHERE TenancyOutGoing.Percent <> 0) THEN DO:
613 debug-event( "Skipping - tenancylease for Rental space '" + RentFlow.RelatedKey + "' has no outgoings.").
614 exclude-lease = Yes.
615 END.
616 ELSE IF TenancyLease.LeaseStatus = "PAST" OR TenancyLease.LeaseStatus = "ASGN" THEN DO:
617 debug-event( "Skipping - tenancylease for Rental space '" + RentFlow.RelatedKey + "' has PAST or ASGN status.").
618 exclude-lease = Yes.
619 END.
620 ELSE IF TenancyLease.LeaseEndDate = ? THEN DO:
621 FIND FIRST OtherFlow WHERE OtherFlow.EntityType = "P"
622 AND OtherFlow.EntityCode = Property.PropertyCode
623 AND (OtherFlow.CashFlowType = "RENT" OR OtherFlow.CashFlowType = "MRNT")
624 AND OtherFlow.Amount = 0
625 AND OtherFlow.RelatedKey = RentFlow.RelatedKey
626 AND OtherFlow.StartDate > TenancyLease.LeaseStartDate NO-LOCK NO-ERROR.
627 IF AVAILABLE(OtherFlow) AND OtherFlow.StartDate <= RentFlow.StartDate THEN DO:
628 debug-event( "Skipping - flow for Rental space '" + RentFlow.RelatedKey + "' "
629 + STRING(RentFlow.StartDate, "99/99/9999") + " appears to be past the end of the existing lease.").
630 exclude-lease = Yes.
631 END.
632 END.
633 ELSE IF TenancyLease.LeaseEndDate < RentFlow.StartDate THEN DO:
634 debug-event( "Skipping - flow for Rental space '" + RentFlow.RelatedKey + "' "
635 + STRING(RentFlow.StartDate, "99/99/9999") + " is past the end of the existing lease.").
636 exclude-lease = yes.
637 END.
638 END.
640 /* Calculate the percentages of all of the PX amounts to create RX amounts */
641 IF NOT(exclude-lease) THEN DO:
642 d-1 = RentFlow.StartDate.
643 d-n = IF RentFlow.EndDate = ? THEN forecast-end ELSE last-of-month( RentFlow.EndDate ).
644 IF d-1 > first-of-month( d-1 ) THEN DO:
645 d-1 = add-months( first-of-month( d-1 ), 1 ).
646 debug-event( RentFlow.RelatedKey + ": Rent flow start after 1st of month " + STRING( RentFlow.StartDate, "99/99/9999")
647 + " - changed to " + STRING( d-1, "99/99/9999") ).
648 END.
649 IF d-n <> RentFlow.EndDate THEN
650 debug-event( RentFlow.RelatedKey + ": Rent flow finish before end of month " + (IF RentFlow.EndDate = ? THEN "?" ELSE STRING( RentFlow.EndDate, "99/99/9999") )
651 + " - changed to " + STRING( d-n, "99/99/9999") ).
653 debug-event( "Making RX records for lease " + STRING(RentalSpace.TenancyLeaseCode)
654 + ", starting on " + STRING(RentFlow.StartDate) + " already processed").
655 RUN make-rx-records( d-1, d-n, No, RentFlow.RelatedKey ).
656 END.
657 END.
659 IF last-rsp-code <> ? THEN DO:
660 /* create flows for the RX amounts */
661 IF profiled THEN RUN profiled-flows. ELSE RUN smoothed-flows.
662 END.
664 END PROCEDURE.
666 /* _UIB-CODE-BLOCK-END */
667 &ANALYZE-RESUME
670 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE parse-options Procedure
671 PROCEDURE parse-options :
672 /*------------------------------------------------------------------------------
673 Purpose: Decode the command-line parameters
674 ------------------------------------------------------------------------------*/
675 DEF VAR i AS INT NO-UNDO.
676 DEF VAR token AS CHAR NO-UNDO.
678 scenario-code = INT( ENTRY( 1, process-options , "~n") ).
680 DO i = 2 TO NUM-ENTRIES( process-options, "~n" ):
681 token = ENTRY( i, process-options, "~n" ).
682 CASE( ENTRY( 1, token ) ):
683 WHEN "Debug" THEN debug-mode = Yes.
684 END CASE.
685 END.
687 END PROCEDURE.
689 /* _UIB-CODE-BLOCK-END */
690 &ANALYZE-RESUME
693 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE profiled-flows Procedure
694 PROCEDURE profiled-flows :
695 /*------------------------------------------------------------------------------
696 Purpose: Create cashflow records for each month, for each account
697 ------------------------------------------------------------------------------*/
699 debug-event( "Creating profiled flows" ).
701 FOR EACH RX BY RX.ac BY RX.mc:
702 CREATE CashFlow.
703 ASSIGN CashFlow.ScenarioCode = Scenario.ScenarioCode
704 CashFlow.EntityType = "P"
705 CashFlow.EntityCode = Property.PropertyCode
706 CashFlow.AccountCode = RX.ac + recovered-offset
707 CashFlow.CashFlowType = "RECV"
708 CashFlow.StartDate = rx.d-start
709 CashFlow.EndDate = rx.d-end
710 CashFlow.RelatedKey = rx.relate
711 CashFlow.FrequencyCode = "MNTH"
712 CashFlow.Amount = rx.amt
713 CashFlow.Description = rx.r-desc.
714 DELETE RX.
715 END.
716 END PROCEDURE.
718 /* _UIB-CODE-BLOCK-END */
719 &ANALYZE-RESUME
722 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE property-cash-flows Procedure
723 PROCEDURE property-cash-flows :
724 /*------------------------------------------------------------------------------
725 Purpose:
726 ------------------------------------------------------------------------------*/
727 DEF BUFFER RentFlow FOR CashFlow.
729 DEF VAR part-month AS DEC NO-UNDO.
730 DEF VAR rsp-code AS INT NO-UNDO.
731 DEF VAR lease-list AS CHAR NO-UNDO.
732 DEF VAR d-1 AS DATE NO-UNDO.
733 DEF VAR d-n AS DATE NO-UNDO.
734 DEF VAR last-rsp-code AS INT NO-UNDO INITIAL ?.
735 DEF VAR lease-key AS CHAR NO-UNDO.
736 DEF VAR space-key AS CHAR NO-UNDO.
738 debug-event( "Processing current leases of property" ).
739 FOR EACH TenancyLease OF Property WHERE TenancyLease.LeaseStatus <> "PAST"
740 AND TenancyLease.LeaseStatus <> "ASGN" NO-LOCK:
741 lease-key = id-code( "TLS" ).
742 debug-event( "Looking at tenancy lease " + lease-key ).
743 RUN clear-rx-records.
744 IF CAN-FIND(FIRST TenancyOutGoing OF TenancyLease WHERE TenancyOutGoing.Percent <> 0) THEN DO:
745 /* Calculate the percentages of all of the PX amounts to create RX amounts */
746 d-1 = TenancyLease.LeaseStartDate.
747 d-n = forecast-end.
749 FOR EACH RentalSpace OF TenancyLease NO-LOCK:
750 space-key = id-code( "RSP" ).
751 FIND FIRST RentFlow OF Scenario WHERE RentFlow.RelatedKey = space-key
752 AND RentFlow.StartDate > d-1
753 AND (RentFlow.CFChangeType = "N"
754 OR RentFlow.CFChangeType = "X")
755 NO-LOCK NO-ERROR.
756 IF AVAILABLE(RentFlow) THEN DO:
757 IF d-n = ? THEN
758 d-n = RentFlow.StartDate - 1.
759 ELSE
760 d-n = MIN( d-n, (RentFlow.StartDate - 1)).
761 END.
762 END.
764 debug-event( "Making RX records for lease " + lease-key ).
765 RUN make-rx-records( d-1, d-n, No, lease-key ).
766 IF profiled THEN RUN profiled-flows. ELSE RUN smoothed-flows.
767 END.
768 ELSE
769 debug-event( "Skipping - tenancylease '" + lease-key + "' has no outgoings.").
771 END.
773 END PROCEDURE.
775 /* _UIB-CODE-BLOCK-END */
776 &ANALYZE-RESUME
779 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE smoothed-flows Procedure
780 PROCEDURE smoothed-flows :
781 /*------------------------------------------------------------------------------
782 Purpose:
783 ------------------------------------------------------------------------------*/
784 DEF VAR d-1 AS DATE NO-UNDO INITIAL ?.
785 DEF VAR amt AS DEC NO-UNDO INITIAL 0.
787 DEF VAR last-ac AS DEC NO-UNDO INITIAL ?.
788 DEF VAR last-end AS DATE NO-UNDO INITIAL ?.
789 DEF VAR last-relate AS CHAR NO-UNDO INITIAL ?.
790 DEF VAR peak-percent AS DEC NO-UNDO INITIAL ?.
791 DEF VAR n AS INT NO-UNDO.
792 DEF VAR next-washup AS DATE NO-UNDO.
794 debug-event( "Creating smoothed flows" ).
795 next-washup = forecast-start - 1.
797 FOR EACH RX BY RX.ac BY RX.mc:
798 IF RX.ac <> last-ac OR RX.d-start > next-washup THEN DO:
799 IF last-ac <> ? THEN
800 RUN create-flow( "RECV", "", last-ac + recovered-offset,
801 d-1, last-end, "MNTH", (amt / n), last-relate,
802 "Recovery of " + STRING( last-ac, "9999.99")
803 + " at " + TRIM(STRING(peak-percent,"->,>>9.99"))
804 + "% smoothed over " + STRING(n) + " months" ).
806 IF RX.ac <> last-ac THEN
807 next-washup = next-date-after( washup-cycle, RX.d-start, "M", 12).
808 ELSE
809 next-washup = add-months( next-washup, 12).
811 ASSIGN last-ac = RX.ac
812 d-1 = RX.d-start
813 amt = 0
814 n = 0
815 peak-percent = RX.percent.
817 debug-event( "Next washup is: " + STRING( next-washup, "99/99/9999") ).
818 END.
819 debug-event( RX.relate + ": " + STRING( RX.ac, "9999.99" ) + ", "
820 + STRING(RX.mc) + ", " + STRING( RX.d-start, "99/99/9999")
821 + ", for " + STRING(RX.amt) ).
823 ASSIGN amt = amt + RX.amt
824 last-end = RX.d-end
825 last-relate = RX.relate
826 n = n + 1
827 peak-percent = MAX( peak-percent, RX.percent ).
828 DELETE RX.
829 END.
831 IF last-ac <> ? THEN
832 RUN create-flow( "RECV", "", last-ac + recovered-offset, d-1, last-end,
833 "MNTH", (amt / n), last-relate,
834 "Recovery of " + STRING( last-ac, "9999.99")
835 + " at " + TRIM(STRING(peak-percent,"->,>>9.99"))
836 + "% smoothed over " + STRING(n) + " months" ).
838 END PROCEDURE.
840 /* _UIB-CODE-BLOCK-END */
841 &ANALYZE-RESUME
844 /* ************************ Function Implementations ***************** */
846 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION check-manual-flow Procedure
847 FUNCTION check-manual-flow RETURNS LOGICAL
848 ( INPUT man-type AS CHAR, INPUT chg-type AS CHAR, INPUT-OUTPUT d-1 AS DATE, INPUT-OUTPUT d-n AS DATE ) :
849 /*------------------------------------------------------------------------------
850 Purpose: Check that no manual cash flow occurs between d-1 and d-n
851 Notes: We adjust the dates if necessary, or perhaps we give up entirely
852 (i.e. RETURN No) if the whole period is occluded.
853 ------------------------------------------------------------------------------*/
854 DEF VAR id-cd AS CHAR NO-UNDO.
856 /* Can't manually override adjustments, except by specifically overwriting the amounts */
857 IF chg-type = "A" THEN DO:
858 IF CAN-FIND( FIRST CashFlow WHERE CashFlow.ScenarioCode = Scenario.ScenarioCode
859 AND CashFlow.RelatedKey = id-cd
860 AND CashFlow.CashFlowType = man-type
861 AND CashFlow.StartDate = d-1
862 AND CashFlow.EndDate = d-n
863 AND CashFlow.CFChangeType = "A") THEN
864 RETURN No.
865 ELSE
866 RETURN Yes.
867 END.
869 id-cd = id-code("TLS").
870 FOR EACH CashFlow NO-LOCK WHERE CashFlow.ScenarioCode = Scenario.ScenarioCode
871 AND CashFlow.RelatedKey = id-cd
872 AND CashFlow.CashFlowType = man-type
873 AND (CashFlow.StartDate <= d-n OR CashFlow.StartDate = ?)
874 AND (CashFlow.EndDate >= d-1 OR CashFlow.EndDate = ?):
876 IF (CashFlow.StartDate <= d-1 OR CashFlow.StartDate = ?)
877 AND (CashFlow.EndDate >= d-n OR CashFlow.EndDate = ?) THEN RETURN No.
879 IF CashFlow.StartDate > d-1 THEN d-n = CashFlow.StartDate - 1.
880 ELSE IF CashFlow.EndDate < d-n THEN d-1 = CashFlow.EndDate + 1.
882 END.
884 RETURN (d-1 <= d-n) OR d-1 = ? OR d-n = ?.
886 END FUNCTION.
888 /* _UIB-CODE-BLOCK-END */
889 &ANALYZE-RESUME
892 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION get-parameter Procedure
893 FUNCTION get-parameter RETURNS CHARACTER
894 ( INPUT parameter-name AS CHAR ) :
895 /*------------------------------------------------------------------------------
896 Purpose:
897 Notes:
898 ------------------------------------------------------------------------------*/
899 IF NOT AVAILABLE Scenario THEN RETURN "".
901 DEF VAR dv AS CHAR NO-UNDO.
903 FIND FIRST ScenarioParameter OF Scenario WHERE
904 ScenarioParameter.ParameterID = parameter-name NO-LOCK NO-ERROR.
906 dv = ( IF AVAILABLE ScenarioParameter THEN ScenarioParameter.Data ELSE "" ).
907 debug-event( "Parameter " + parameter-name + "=" + dv ).
909 RETURN dv.
911 END FUNCTION.
913 /* _UIB-CODE-BLOCK-END */
914 &ANALYZE-RESUME
917 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION id-code Procedure
918 FUNCTION id-code RETURNS CHARACTER
919 ( INPUT type AS CHAR ) :
920 /*------------------------------------------------------------------------------
921 Purpose:
922 Notes: Record appropriate to type must be available
923 ------------------------------------------------------------------------------*/
924 IF type = "TLS" AND AVAILABLE(TenancyLease) THEN
925 RETURN "TLS," + STRING( TenancyLease.TenancyLeaseCode, "99999" ).
926 ELSE IF AVAILABLE(RentalSpace) THEN
927 RETURN "RSP," + STRING( RentalSpace.PropertyCode, "99999" )
928 + ",L," + STRING( 50000 + RentalSpace.Level, "99999" )
929 + ",S," + STRING( 50000 + RentalSpace.LevelSequence, "99999" )
930 + ",R," + STRING( RentalSpace.RentalSpaceCode ).
931 ELSE IF AVAILABLE(Contract) THEN
932 RETURN "SVC," + STRING( Contract.PropertyCode, "99999" )
933 + ",T," + Contract.ServiceType
934 + ",C," + STRING( Contract.CreditorCode, "99999" ).
935 ELSE
936 MESSAGE "Don't know how to make an id code - no appropriate records available".
938 END FUNCTION.
940 /* _UIB-CODE-BLOCK-END */
941 &ANALYZE-RESUME
944 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION include-property Procedure
945 FUNCTION include-property RETURNS LOGICAL
946 ( /* parameter-definitions */ ) :
947 /*------------------------------------------------------------------------------
948 Purpose:
949 Notes:
950 ------------------------------------------------------------------------------*/
951 DEF VAR include-it AS LOGI NO-UNDO.
953 IF all-entities THEN RETURN Property.Active .
954 IF entity-list-type <> "P" THEN RETURN No.
956 CASE entity-list-by:
957 WHEN "Company" THEN
958 include-it = LOOKUP( STRING( Property.PropertyCode ), entity-list ) <> 0.
960 WHEN "Properties" THEN
961 include-it = LOOKUP( STRING( Property.PropertyCode ), entity-list ) <> 0.
963 WHEN "Property Managers" THEN
964 include-it = LOOKUP( STRING( Property.Administrator ), entity-list ) <> 0.
966 WHEN "Portfolios" THEN
967 include-it = LOOKUP( STRING( Property.Manager ), entity-list ) <> 0.
969 WHEN "Regions" THEN
970 include-it = LOOKUP( Property.Region, entity-list ) <> 0.
971 END CASE.
973 RETURN include-it.
975 END FUNCTION.
977 /* _UIB-CODE-BLOCK-END */
978 &ANALYZE-RESUME
981 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION is-recoverable Procedure
982 FUNCTION is-recoverable RETURNS LOGICAL
983 ( INPUT ac AS DEC ) :
984 /*------------------------------------------------------------------------------
985 Purpose: Determine if the account 'ac' is recoverable
986 ------------------------------------------------------------------------------*/
987 DEF BUFFER COA FOR ChartOfAccount.
989 FIND COA NO-LOCK WHERE COA.AccountCode = ac NO-ERROR.
990 IF NOT AVAILABLE(COA) THEN RETURN No.
992 RETURN LOOKUP( COA.AccountGroupCode, recoverable-groups) > 0 .
994 END FUNCTION.
996 /* _UIB-CODE-BLOCK-END */
997 &ANALYZE-RESUME