1 &ANALYZE-SUSPEND _VERSION-NUMBER UIB_v8r12
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.
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
28 ASSIGN CashFlow.Sequence
= IF AVAILABLE LastCashFlow
THEN
29 LastCashFlow.Sequence
+ 1 ELSE 1.
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
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
66 /* _UIB-CODE-BLOCK-END
*/
70 &ANALYZE-SUSPEND _UIB-PREPROCESSOR-BLOCK
72 /* ******************** Preprocessor Definitions
******************** */
74 &Scoped-define PROCEDURE-TYPE Procedure
78 /* _UIB-PREPROCESSOR-BLOCK-END
*/
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
*/
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
*/
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
*/
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
*/
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
*/
120 /* *********************** Procedure Settings
************************ */
122 &ANALYZE-SUSPEND _PROCEDURE-SETTINGS
123 /* Settings for
THIS-PROCEDURE
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
139 /* END WINDOW DEFINITION
*/
145 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _INCLUDED-LIB Procedure
146 /* ************************* Included-Libraries
*********************** */
148 {inc
/method
/m-debug.i
}
151 /* _UIB-CODE-BLOCK-END
*/
156 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _MAIN-BLOCK Procedure
159 /* *************************** Main Block
*************************** */
160 &SCOP KEEP-DEBUG-MESSAGES KEEP-MESSAGES
163 FIND Scenario
WHERE Scenario.ScenarioCode
= scenario-code
NO-LOCK.
165 debug-event
("Starting").
167 RUN delete-current-cash-flows.
168 RUN generate-recoveries.
170 debug-event
("Finished").
173 MESSAGE "Forecast Recovery Regeneration Complete" VIEW-AS ALERT-BOX INFORMATION
178 /* _UIB-CODE-BLOCK-END
*/
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:
224 PX.ac
= CashFlow.AccountCode.
225 PX.mc
= Month.MonthCode.
227 PX.d-start
= Month.StartDate.
228 PX.d-end
= Month.EndDate.
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
).
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
).
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
+ "'").
251 FIND FIRST PX
WHERE PX.ac
= CashFlow.AccountCode
252 AND PX.mc
= Month.MonthCode
NO-ERROR.
253 IF NOT AVAILABLE(PX
) THEN DO:
255 PX.ac
= CashFlow.AccountCode.
256 PX.mc
= Month.MonthCode.
258 PX.d-start
= Month.StartDate.
259 PX.d-end
= Month.EndDate.
261 PX.amt
= PX.amt
+ DEC(ENTRY(i
,flows
)).
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
):
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:
281 PX.mc
= Month.MonthCode.
283 PX.d-start
= Month.StartDate.
284 PX.d-end
= Month.EndDate.
287 FIND FIRST PX
WHERE PX.ac
> ths-ac
NO-ERROR.
292 /* _UIB-CODE-BLOCK-END
*/
296 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE clear-rx-records Procedure
297 PROCEDURE clear-rx-records
:
298 /*------------------------------------------------------------------------------
300 ------------------------------------------------------------------------------*/
301 FOR EACH RX
: DELETE RX.
END.
305 /* _UIB-CODE-BLOCK-END
*/
309 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE create-flow Procedure
310 PROCEDURE create-flow
:
311 /*------------------------------------------------------------------------------
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.
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
).
357 /* _UIB-CODE-BLOCK-END
*/
361 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE delete-current-cash-flows Procedure
362 PROCEDURE delete-current-cash-flows
:
363 /*------------------------------------------------------------------------------
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":
377 /* _UIB-CODE-BLOCK-END
*/
381 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE each-tenancy-lease Procedure
382 PROCEDURE each-tenancy-lease
:
383 /*------------------------------------------------------------------------------
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.
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") + ",".
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
).
414 /* _UIB-CODE-BLOCK-END
*/
418 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE generate-recoveries Procedure
419 PROCEDURE generate-recoveries
:
420 /*------------------------------------------------------------------------------
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.
436 /* _UIB-CODE-BLOCK-END
*/
440 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE get-parameters Procedure
441 PROCEDURE get-parameters
:
442 /*------------------------------------------------------------------------------
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" ).
465 recovered-offset
= DEC( parm
).
467 recovered-offset
= 0.2 .
471 /* _UIB-CODE-BLOCK-END
*/
475 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE make-rx-records Procedure
476 PROCEDURE make-rx-records
:
477 /*------------------------------------------------------------------------------
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
).
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") ).
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") ).
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
) .
522 BUFFER-COPY PX
TO RX
ASSIGN
523 RX.percent
= RentalSpace.OutGoingsPercentage
* part-month
524 RX.amt
= - (PX.amt
* (RX.percent
/ 100))
526 RX.r-desc
= "Recover " + TRIM( STRING( RX.percent
, "->,>>9.99"))
527 + "% of " + TRIM( STRING( PX.amt
, "->>,>>>,>>9.99")).
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
) .
540 BUFFER-COPY PX
TO RX
ASSIGN
541 RX.percent
= TenancyOutgoing.Percentage
* part-month
542 RX.amt
= - (PX.amt
* (RX.percent
/ 100))
544 RX.r-desc
= "Recover " + TRIM( STRING( RX.percent
, "->,>>9.99"))
545 + "% of " + TRIM( STRING( PX.amt
, "->>,>>>,>>9.99")).
551 /* _UIB-CODE-BLOCK-END
*/
555 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE old-property-cash-flows Procedure
556 PROCEDURE old-property-cash-flows
:
557 /*------------------------------------------------------------------------------
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.
584 last-rsp-code
= rsp-code.
585 RUN clear-rx-records.
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!").
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").
603 lease-list
= lease-list
+ STRING(RentalSpace.TenancyLeaseCode
) + "-" + STRING(RentFlow.StartDate
) + ",".
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
+ "'").
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.").
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.").
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.").
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.").
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") ).
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
).
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.
666 /* _UIB-CODE-BLOCK-END
*/
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.
689 /* _UIB-CODE-BLOCK-END
*/
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
:
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.
718 /* _UIB-CODE-BLOCK-END
*/
722 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE property-cash-flows Procedure
723 PROCEDURE property-cash-flows
:
724 /*------------------------------------------------------------------------------
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.
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")
756 IF AVAILABLE(RentFlow
) THEN DO:
758 d-n
= RentFlow.StartDate
- 1.
760 d-n
= MIN( d-n
, (RentFlow.StartDate
- 1)).
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.
769 debug-event
( "Skipping - tenancylease '" + lease-key
+ "' has no outgoings.").
775 /* _UIB-CODE-BLOCK-END
*/
779 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE smoothed-flows Procedure
780 PROCEDURE smoothed-flows
:
781 /*------------------------------------------------------------------------------
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:
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).
809 next-washup
= add-months
( next-washup
, 12).
811 ASSIGN last-ac
= RX.ac
815 peak-percent
= RX.percent.
817 debug-event
( "Next washup is: " + STRING( next-washup
, "99/99/9999") ).
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
825 last-relate
= RX.relate
827 peak-percent
= MAX( peak-percent
, RX.percent
).
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" ).
840 /* _UIB-CODE-BLOCK-END
*/
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
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.
884 RETURN (d-1
<= d-n
) OR d-1
= ?
OR d-n
= ?.
888 /* _UIB-CODE-BLOCK-END
*/
892 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION get-parameter Procedure
893 FUNCTION get-parameter
RETURNS CHARACTER
894 ( INPUT parameter-name
AS CHAR ) :
895 /*------------------------------------------------------------------------------
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
).
913 /* _UIB-CODE-BLOCK-END
*/
917 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION id-code Procedure
918 FUNCTION id-code
RETURNS CHARACTER
919 ( INPUT type
AS CHAR ) :
920 /*------------------------------------------------------------------------------
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" ).
936 MESSAGE "Don't know how to make an id code - no appropriate records available".
940 /* _UIB-CODE-BLOCK-END
*/
944 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION include-property Procedure
945 FUNCTION include-property
RETURNS LOGICAL
946 ( /* parameter-definitions
*/ ) :
947 /*------------------------------------------------------------------------------
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.
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.
970 include-it
= LOOKUP( Property.Region
, entity-list
) <> 0.
977 /* _UIB-CODE-BLOCK-END
*/
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 .
996 /* _UIB-CODE-BLOCK-END
*/