Really, this should be it, for the passing income.
[capital-apms-progress.git] / inc / cashflow.i
blobb497902c957f643db6db3165eec452c2692e5d90
1 &ANALYZE-SUSPEND _VERSION-NUMBER UIB_v8r12
2 &ANALYZE-RESUME
3 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _DEFINITIONS Include
4 /*--------------------------------------------------------------------------
5 ------------------------------------------------------------------------*/
7 DEF VAR cf-split-date AS CHAR NO-UNDO.
8 DEF VAR cf-split-info AS CHAR NO-UNDO.
10 /* _UIB-CODE-BLOCK-END */
11 &ANALYZE-RESUME
14 &ANALYZE-SUSPEND _UIB-PREPROCESSOR-BLOCK
16 /* ******************** Preprocessor Definitions ******************** */
20 /* _UIB-PREPROCESSOR-BLOCK-END */
21 &ANALYZE-RESUME
24 /* ************************ Function Prototypes ********************** */
26 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD cf-add-to-bucket Include
27 FUNCTION cf-add-to-bucket RETURNS CHARACTER
28 ( INPUT bucket-id AS CHAR, INPUT amount AS DEC ) FORWARD.
30 /* _UIB-CODE-BLOCK-END */
31 &ANALYZE-RESUME
33 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD cf-find-bucket Include
34 FUNCTION cf-find-bucket RETURNS CHARACTER
35 ( INPUT d-on AS DATE, INPUT d-1 AS DATE, INPUT d-n AS DATE, INPUT mthly AS LOGICAL, INPUT units AS INT ) FORWARD.
37 /* _UIB-CODE-BLOCK-END */
38 &ANALYZE-RESUME
40 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD end-of-bucket Include
41 FUNCTION end-of-bucket RETURNS DATE
42 ( INPUT ends AS CHAR ) FORWARD.
44 /* _UIB-CODE-BLOCK-END */
45 &ANALYZE-RESUME
47 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD flow-on-1st Include
48 FUNCTION flow-on-1st RETURNS LOGICAL
49 ( INPUT cf-type AS CHAR, cf-freq AS CHAR ) FORWARD.
51 /* _UIB-CODE-BLOCK-END */
52 &ANALYZE-RESUME
54 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION-FORWARD start-of-bucket Include
55 FUNCTION start-of-bucket RETURNS DATE
56 ( INPUT ends AS CHAR ) FORWARD.
58 /* _UIB-CODE-BLOCK-END */
59 &ANALYZE-RESUME
62 /* *********************** Procedure Settings ************************ */
64 &ANALYZE-SUSPEND _PROCEDURE-SETTINGS
65 /* Settings for THIS-PROCEDURE
66 Type: Include
67 Allow:
68 Frames: 0
69 Add Fields to: Neither
70 Other Settings: INCLUDE-ONLY
72 &ANALYZE-RESUME _END-PROCEDURE-SETTINGS
74 /* ************************* Create Window ************************** */
76 &ANALYZE-SUSPEND _CREATE-WINDOW
77 /* DESIGN Window definition (used by the UIB)
78 CREATE WINDOW Include ASSIGN
79 HEIGHT = .33
80 WIDTH = 40.
81 /* END WINDOW DEFINITION */
83 &ANALYZE-RESUME
87 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _INCLUDED-LIB Include
88 /* ************************* Included-Libraries *********************** */
90 {inc/string.i}
91 {inc/date.i}
93 /* _UIB-CODE-BLOCK-END */
94 &ANALYZE-RESUME
98 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _CUSTOM _MAIN-BLOCK Include
101 /* *************************** Main Block *************************** */
103 /* _UIB-CODE-BLOCK-END */
104 &ANALYZE-RESUME
107 /* ********************** Internal Procedures *********************** */
109 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE dump-cash-flow Include
110 PROCEDURE dump-cash-flow :
111 /*------------------------------------------------------------------------------
112 Purpose:
113 ------------------------------------------------------------------------------*/
114 DEF INPUT PARAMETER names AS CHAR NO-UNDO.
115 DEF INPUT PARAMETER flows AS CHAR NO-UNDO.
116 DEF INPUT PARAMETER changes AS CHAR NO-UNDO.
118 DEF VAR line AS CHAR NO-UNDO.
120 line = STRING( CashFlow.ScenarioCode, ">>>9") + " "
121 + CashFlow.EntityType + STRING( CashFlow.EntityCode, "99999") + "-" + STRING( CashFlow.AccountCode, "9999.99")
122 + CashFlow.CFChangeType + " " + CashFlow.CashFlowType + " " + CashFlow.FrequencyCode + " "
123 + (IF CashFlow.StartDate = ? THEN "?" ELSE STRING( CashFlow.StartDate, "99/99/9999")) + " "
124 + (IF CashFlow.EndDate = ? THEN "?" ELSE STRING( CashFlow.EndDate, "99/99/9999")) + " "
125 + STRING( CashFlow.Amount, "->>,>>>,>>9.99") + " "
126 + CashFlow.RelatedKey + " Change:" + changes.
127 debug-event( line ).
129 END PROCEDURE.
131 /* _UIB-CODE-BLOCK-END */
132 &ANALYZE-RESUME
135 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE split-cash-flow Include
136 PROCEDURE split-cash-flow :
137 /*------------------------------------------------------------------------------
138 Purpose: Split the cash flow into the occurrences during the period.
139 ------------------------------------------------------------------------------*/
140 DEF INPUT PARAM fc-1 AS DATE NO-UNDO. /* fc = forecast */
141 DEF INPUT PARAM fc-n AS DATE NO-UNDO.
142 DEF INPUT PARAM fc-fq AS CHAR NO-UNDO.
143 DEF INPUT PARAM fw-1 AS DATE NO-UNDO. /* fw = cash flow */
144 DEF INPUT PARAM fw-n AS DATE NO-UNDO.
145 DEF INPUT PARAM fw-fq AS CHAR NO-UNDO.
146 DEF INPUT PARAM fw-amt AS DEC NO-UNDO.
147 DEF INPUT PARAM fw-1st AS LOGI NO-UNDO.
148 DEF OUTPUT PARAM split-dates AS CHAR NO-UNDO.
149 DEF OUTPUT PARAM split-flow AS CHAR NO-UNDO.
151 cf-split-date = "". cf-split-info = "".
152 IF fw-1 = ? THEN fw-1 = fc-1.
153 IF fw-n = ? THEN fw-n = fc-n.
155 /* find out about the periods we're dealing with */
156 DEF VAR fc-units AS INT NO-UNDO. DEF VAR fc-mthly AS LOGI NO-UNDO.
157 DEF VAR fw-units AS INT NO-UNDO. DEF VAR fw-mthly AS LOGI NO-UNDO.
158 fc-units = get-freq-months( fc-fq ).
159 fc-mthly = (fc-units <> 0 AND fc-units <> ?).
160 IF NOT fc-mthly THEN fc-units = get-freq-days( fc-fq ).
162 fw-units = get-freq-months( fw-fq ).
163 fw-mthly = (fw-units <> 0 AND fw-units <> ?).
164 IF NOT fw-mthly THEN fw-units = get-freq-days( fw-fq ).
166 IF fc-units = 0 OR fw-units = 0 OR fc-units = ? OR fw-units = ? THEN DO:
167 MESSAGE fw-fq "seems to be an ill-defined frequency!"
168 VIEW-AS ALERT-BOX INFORMATION.
169 RETURN.
170 END.
171 IF fc-mthly THEN ASSIGN fc-1 = first-of-month( fc-1 )
172 fc-n = last-of-month( fc-n ).
174 /* Split the cash flow into the appropriate buckets */
175 DEF VAR bucket AS CHAR NO-UNDO.
176 DEF VAR pay-no AS INT NO-UNDO.
177 DEF VAR pay-1 AS DATE NO-UNDO.
178 DEF VAR pay-d AS DATE NO-UNDO.
179 pay-1 = next-date-after( fw-1, fc-1, (IF fw-mthly THEN "M" ELSE "D"), fw-units).
180 IF fw-1st THEN pay-1 = first-of-month(pay-1).
182 DEF VAR b-1 AS DATE NO-UNDO.
183 DEF VAR b-n AS DATE NO-UNDO.
184 DEF VAR part-period AS DEC NO-UNDO INITIAL 1.
186 &IF DEFINED(DEBUG-END) &THEN
187 debug-event("Splitting Flow: fc-1=" + STRING( fc-1, "99/99/9999")
188 + ", fc-n=" + STRING( fc-n, "99/99/9999")
189 + ", fc-fq=" + fc-fq
190 + " = " + STRING(fc-units) + (IF fc-mthly THEN "M" ELSE "D")
191 + ", fw-1=" + STRING( fw-1, "99/99/9999")
192 + ", fw-n=" + STRING( fw-n, "99/99/9999")
193 + ", fw-fq=" + fw-fq
194 + " = " + STRING(fw-units) + (IF fw-mthly THEN "M" ELSE "D")
195 + ", fw-1st=" + STRING( fw-1st, "Yes/No")
196 + ", fw-amt=" + STRING( fw-amt ) ).
197 &ENDIF
199 pay-d = pay-1.
200 DO WHILE pay-d <= fc-n AND pay-d <= fw-n:
202 /* add this pay into the appropriate bucket */
203 bucket = cf-find-bucket( pay-d, fc-1, fc-n, fc-mthly, fc-units ).
204 b-1 = start-of-bucket(bucket).
205 b-n = end-of-bucket(bucket).
206 IF (fw-1 > b-1 OR fw-n < b-n)
207 AND fw-mthly AND fc-mthly AND fc-units >= fw-units THEN DO:
208 part-period = (MIN(fw-n, b-n) - MAX(fw-1, b-1) + 1) / (b-n - b-1 + 1).
210 &IF DEFINED(DEBUG-END) &THEN
211 debug-event("Part period: fw-1=" + STRING( fw-1, "99/99/9999")
212 + ", fw-n=" + STRING( fw-n, "99/99/9999")
213 + ", b-1=" + STRING( b-1, "99/99/9999")
214 + ", b-n=" + STRING( b-n, "99/99/9999")
215 + ", pay-d=" + STRING( pay-d, "99/99/9999")
216 + ", part=" + STRING( part-period ) ).
217 &ENDIF
219 IF part-period > 1 THEN part-period = 1.
220 IF part-period > 0 THEN
221 cf-add-to-bucket( bucket, fw-amt * part-period ).
222 END.
223 ELSE
224 cf-add-to-bucket( bucket, fw-amt ).
226 /* Get the next pay date */
227 pay-no = pay-no + 1.
228 IF fw-mthly THEN pay-d = add-months( pay-1, fw-units * pay-no ).
229 ELSE pay-d = pay-d + fw-units.
230 END.
232 split-dates = cf-split-date.
233 split-flow = cf-split-info.
235 END PROCEDURE.
237 /* _UIB-CODE-BLOCK-END */
238 &ANALYZE-RESUME
241 /* ************************ Function Implementations ***************** */
243 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION cf-add-to-bucket Include
244 FUNCTION cf-add-to-bucket RETURNS CHARACTER
245 ( INPUT bucket-id AS CHAR, INPUT amount AS DEC ) :
246 /*------------------------------------------------------------------------------
247 Purpose:
248 Notes:
249 ------------------------------------------------------------------------------*/
251 DEF VAR list-idx AS INT NO-UNDO.
253 &IF DEFINED(DEBUG-END) &THEN
254 debug-event( "Adding flow to " + bucket-id + " of " + STRING(amount)).
255 &ENDIF
257 list-idx = LOOKUP( bucket-id, cf-split-date ).
258 IF list-idx = 0 THEN DO:
259 add-to-list( cf-split-date, bucket-id ).
260 add-to-list( cf-split-info, STRING(amount) ).
261 END.
262 ELSE
263 ENTRY(list-idx, cf-split-info) = STRING( DEC(ENTRY(list-idx, cf-split-info)) + amount ).
265 RETURN "".
267 END FUNCTION.
269 /* _UIB-CODE-BLOCK-END */
270 &ANALYZE-RESUME
273 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION cf-find-bucket Include
274 FUNCTION cf-find-bucket RETURNS CHARACTER
275 ( INPUT d-on AS DATE, INPUT d-1 AS DATE, INPUT d-n AS DATE, INPUT mthly AS LOGICAL, INPUT units AS INT ) :
276 /*------------------------------------------------------------------------------
277 Purpose:
278 Notes:
279 ------------------------------------------------------------------------------*/
280 DEF VAR b-gin AS DATE NO-UNDO.
281 DEF VAR b-end AS DATE NO-UNDO.
283 /* find the first start-date after this one */
284 b-gin = next-date-after( d-1, d-on + 1, (IF mthly THEN "M" ELSE "D"), units).
285 b-end = b-gin - 1.
286 IF mthly THEN b-gin = add-months(b-gin, - units).
287 ELSE b-gin = b-gin - units.
289 RETURN STRING(b-gin, "99/99/9999") + "-" + STRING(b-end, "99/99/9999").
292 END FUNCTION.
294 /* _UIB-CODE-BLOCK-END */
295 &ANALYZE-RESUME
298 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION end-of-bucket Include
299 FUNCTION end-of-bucket RETURNS DATE
300 ( INPUT ends AS CHAR ) :
301 /*------------------------------------------------------------------------------
302 Purpose:
303 Notes:
304 ------------------------------------------------------------------------------*/
306 RETURN DATE( ENTRY(2,ends,"-")).
308 END FUNCTION.
310 /* _UIB-CODE-BLOCK-END */
311 &ANALYZE-RESUME
314 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION flow-on-1st Include
315 FUNCTION flow-on-1st RETURNS LOGICAL
316 ( INPUT cf-type AS CHAR, cf-freq AS CHAR ) :
317 /*------------------------------------------------------------------------------
318 Purpose: Decide whether the cashflow is forced to the 1st of the month
319 Notes: basically, monthly rentals are done this way.
320 ------------------------------------------------------------------------------*/
322 RETURN cf-freq = "MNTH" AND
323 (cf-type = "RENT" OR cf-type = "MRNT"
324 OR cf-type = "OPEX" OR cf-type = "MOPX" ).
326 END FUNCTION.
328 /* _UIB-CODE-BLOCK-END */
329 &ANALYZE-RESUME
332 &ANALYZE-SUSPEND _UIB-CODE-BLOCK _FUNCTION start-of-bucket Include
333 FUNCTION start-of-bucket RETURNS DATE
334 ( INPUT ends AS CHAR ) :
335 /*------------------------------------------------------------------------------
336 Purpose:
337 Notes:
338 ------------------------------------------------------------------------------*/
340 RETURN DATE( ENTRY(1,ends,"-")).
342 END FUNCTION.
344 /* _UIB-CODE-BLOCK-END */
345 &ANALYZE-RESUME