Loading...
Searching...
No Matches
postdata.sas
Go to the documentation of this file.
1/**
2 @file postdata.sas
3 @brief Either returns the file diffs or actually loads the data to target
4 @details Before loading the target, a check is made against the time the
5 target was last updated (backend) and the time the DIFF was generated
6 (frontend). If the target was updated whilst the DIFF was on the screen,
7 then the provided diff may have been incorrect and so a new DIFF should be
8 generated and approved before load.
9
10 Only 100 rows (of each DIFF type) are displayed on the DIFF screen.
11
12 <h4> Service Inputs </h4>
13
14 <h5> SASCONTROLTABLE </h5>
15 |ACTION:$char10.|TABLE:$char32.|DIFFTIME:$char29.|
16 |---|---|---|
17 |SHOW_DIFFS|DC20220208T142124517_124703_1184|"Tue, 08 Feb 2022 14:23:05 GMT"|
18
19 <h4> SAS Macros </h4>
20 @li bitemporal_dataloader.sas
21 @li dc_assignlib.sas
22 @li dc_cassave.sas
23 @li mf_existds.sas
24 @li mf_existvar.sas
25 @li mf_getattrn.sas
26 @li mf_getengine.sas
27 @li mf_getquotedstr.sas
28 @li mf_getuniquelibref.sas
29 @li mf_getuser.sas
30 @li mf_getvarlist.sas
31 @li mf_nobs.sas
32 @li mf_verifymacvars.sas
33 @li mp_abort.sas
34 @li mp_cntlout.sas
35 @li mp_lockanytable.sas
36 @li mpe_accesscheck.sas
37 @li mpe_alerts.sas
38 @li mpe_runhook.sas
39 @li mpe_targetloader.sas
40 @li removecolsfromwork.sas
41
42
43 @version 9.2
44 @author 4GL Apps Ltd
45 @copyright 4GL Apps Ltd. This code may only be used within Data Controller
46 and may not be re-distributed or re-sold without the express permission of
47 4GL Apps Ltd.
48
49**/
50
51/* this could be a config setting if required */
52%let maxdiff=100;
53
54%mpeinit()
55
56/* load parameters */
57data _null_;
58 set work.sascontroltable;
59 call symputx('ACTION',ACTION);
60 call symputx('LOAD_REF',TABLE);
61 /* DIFFTIME is when the DIFF was generated on the frontend */
62 call symputx('DIFFTIME',DIFFTIME);
63 putlog (_all_)(=);
64run;
65
66%global action is_err err_msg msg;
67%let is_err=0;
68
69%let user=%mf_getuser();
70%let sastime=%sysfunc(datetime());
71data sastime;
72 dt_sastime=&sastime;
73run;
74
75PROC FORMAT;
76 picture yymmddhhmmss other='%0Y-%0m-%0d %0H:%0M:%0S' (datatype=datetime);
77 picture flatdate other='%0Y%0m%0d_%0H%0M%0S' (datatype=datetime);
78RUN;
79
80/* SHOW_DIFFS works by getting the temp tables from the bitemporal loader */
81/* so we share much of the logic from the actual load process */
82%let isfmtcat=0;
83data APPROVE1;
84 set &mpelib..mpe_submit;
85 where TABLE_ID="&LOAD_REF";
86 /* fetch mpe_submit data */
87 libds=cats(base_lib,'.',base_ds);
88 REVIEWED_ON=put(reviewed_on_dttm,datetime19.);
89 call symputx('REVIEW_STATUS_ID',submit_status_cd,'l');
90 call symputx('NUM_OF_APPROVALS_REQUIRED',NUM_OF_APPROVALS_REQUIRED);
91 call symputx('num_of_approvals_remaining',num_of_approvals_remaining);
92
93 /* other stuff that's useful to do in data step */
94 call symputx('orig_libds',libds);
95 call symputx('libds',libds);
96 if substr(cats(reverse(libds)),1,3)=:'CF-' then do;
97 libds=scan(libds,1,'-');
98 putlog "Format Catalog Captured";
99 call symputx('isfmtcat',1);
100 libds='work.fmtextract';
101 call symputx('libds',libds);
102 end;
103 putlog (_all_)(=);
104 /* convert provided string DIFFTIME back to a numeric SAS datetime */
105 if "&action" ne "SHOW_DIFFS" then do;
106 call symputx('DIFFTIME',input(symget('DIFFTIME'),anydtdtm18.));
107 end;
108 length difftime $32;
109 DIFFTIME=put(&sastime,datetime19.2);
110run;
111
112%mp_cntlout(
113 iftrue=(&isfmtcat=1)
114 ,libcat=&orig_libds
115 ,fmtlist=0
116 ,cntlout=work.fmtextract
117)
118
119%mp_abort(
120 iftrue=(%mf_verifymacvars(difftime orig_libds libds load_ref)=0)
121 ,mac=&_program
122 ,msg=%str(Missing: difftime orig_libds libds load_ref)
123)
124
125/* security checks */
126%mpe_accesscheck(&orig_libds,outds=authEDIT,user=&user,access_level=EDIT)
127%mpe_accesscheck(&orig_libds,outds=authAPP,user=&user,access_level=APPROVE)
128
129%mp_abort(iftrue= (&syscc ne 0)
130 ,mac=&_program
131 ,msg=%str(syscc=&syscc Before entering postdata macro)
132)
133
134%mp_abort(
135 iftrue=(
136 %mf_getattrn(work.authEDIT,NLOBS)=0 & %mf_getattrn(work.authAPP,NLOBS)=0
137 )
138 ,mac=&_program
139 ,msg=%str(&user not authorised to view approval screen for &orig_libds)
140)
141
142%macro quickmacro(inds,outds);
143 data &outds ;
144 %if %length(&VAR_BUSFROM)>0 %then %do;
145 format &VAR_BUSFROM &VAR_BUSTO yymmddhhmmss.;
146 %end;
147 if 0 then set &emptybasetable;
148 set &inds;
149 %if %mf_existvar(&libds,&var_txfrom) %then %do;
150 drop &var_txfrom &var_txto;
151 %end;
152 %if %mf_existvar(&inds,_____DELETE__THIS__RECORD_____) %then %do;
153 drop _____DELETE__THIS__RECORD_____;
154 %end;
155 %if %mf_existvar(&inds,&VAR_PROCESSED) %then %do;
156 drop &VAR_PROCESSED;
157 %end;
158 run;
159%mend quickmacro;
160
161%macro postdata();
162
163%if %quote(&REVIEW_STATUS_ID)=%quote(REJECTED)
164 or %quote(&REVIEW_STATUS_ID)=%quote(APPROVED) %then
165%do;
166 data params; set approve1; run;
167 %webout(OPEN)
168 %webout(OBJ,PARAMS)
169 %webout(CLOSE)
170 %return;
171%end;
172
173%mp_abort(iftrue= (&syscc ne 0)
174 ,mac=&_program..sas
175 ,msg=%str(syscc=&syscc)
176)
177
178%if &action=APPROVE_TABLE %then %do;
179
180 /* check user is authorised to approve table */
181 /* user could be an editor but not an approver */
182 %mp_abort(iftrue= (%mf_getattrn(work.authAPP,NLOBS)=0)
183 ,mac=&_program
184 ,msg=%str(&user may not APPROVE changes)
185 )
186
187 /* see if this user has already submitted an approval */
188 %let prev_upload_check=1;
189 proc sql;
190 select count(*) into: prev_upload_check from &mpelib..mpe_review
191 where TABLE_ID="&LOAD_REF" and REVIEWED_BY_NM="&user"
192 and REVIEW_STATUS_ID ne "SUBMITTED";
193 %let authcheck=%mf_getattrn(work.authAPP,NLOBS);
194 %if &authcheck=0 or &prev_upload_check=1 %then %do;
195 %put %str(WARN)ING: &=authcheck &=prev_upload_check;
196 data apPARAMS;
197 AUTHORISED=&authcheck;
198 PREV_UPLOAD_CHECK=&prev_upload_check;
199 run;
200 %webout(OPEN)
201 %webout(OBJ,apPARAMS);
202 %webout(CLOSE)
203 %return;
204 %end;
205
206 /* now check if table has been updated since DIFF screen shown */
207 %local fmt_tm usernm last_load etlsource;
208 %let last_load=0;
209 proc sql noprint;
210 select max(processed_dttm) format=16.2 into: last_load
211 from &mpelib..mpe_dataloads
212 where libref="%scan(&orig_libds,1,.)" and dsn="%scan(&orig_libds,2,.)";
213 select processed_dttm format=datetime19., user_nm, etlsource
214 into: fmt_tm, :usernm, :etlsource
215 from &mpelib..mpe_dataloads
216 where libref="%scan(&orig_libds,1,.)" and dsn="%scan(&orig_libds,2,.)"
217 and processed_dttm=&last_load;
218 %put TIMECHECK: &last_load>&difftime;
219 %if %sysevalf(&last_load>&difftime,boolean)=1 %then %do;
220 %let is_err=1;
221 %let err_msg=&orig_libds was updated in batch %trim(&etlsource
222 ) by %trim(&usernm) on &fmt_tm - please refresh the page!!;
223 %return;
224 %end;
225 %if &syscc ne 0 %then %do;
226 %let is_err=1;
227 %let err_msg=syscc=&syscc before logchange;
228 %return;
229 %end;
230
231 /* upload about to commence so ensure logs */
232 options notes mprint source2;
233 %local oldloc;
234 %if %symexist(SYSPRINTTOLOG) %then %let oldloc=&SYSPRINTTOLOG;
235 %else %let oldloc=%qsysfunc(getoption(LOG));
236 %if %length(&oldloc)>0 %then %do;
237 proc printto
238 log="&mpelocapprovals/&LOAD_REF/approval.log";
239 run;
240 data _null_;
241 if _n_=1 then do;
242 length oldloc $1000;
243 oldloc=symget('oldloc');
244 putlog "****** redirected:" oldloc " *****";
245 end;
246 infile &oldloc;
247 input; putlog _infile_;
248 run;
249 %end;
250 %else %do;
251 proc printto
252 log="&mpelocapprovals/&LOAD_REF/approval.log";
253 run;
254 %end;
255
256 %if &syscc ne 0 %then %do;
257 %let is_err=1;
258 %let err_msg=syscc=&syscc after logchange;
259 %return;
260 %end;
261%end;
262
263/**
264 * upload the actual table
265 */
266%local libref ds;
267%let libref=%scan(&orig_libds,1,.);
268%let ds=%scan(&orig_libds,2,.);
269
270proc sql noprint;
271select PRE_APPROVE_HOOK, POST_APPROVE_HOOK, LOADTYPE, var_txfrom, var_txto
272 ,BUSKEY, VAR_BUSFROM, VAR_BUSTO
273 ,AUDIT_LIBDS, NOTES, coalesce(NUM_OF_APPROVALS_REQUIRED,1)
274 ,VAR_PROCESSED
275 into: PRE_APPROVE_HOOK, :POST_APPROVE_HOOK, :LOADTYPE,:var_txfrom,:var_txto
276 ,:BUSKEY,:VAR_BUSFROM,:VAR_BUSTO
277 ,:AUDIT_LIBDS, :TABLE_DESC, :NUM_OF_APPROVALS_REQUIRED_TOT
278 ,:VAR_PROCESSED
279 from &mpelib..mpe_tables
280 where &dc_dttmtfmt. lt tx_to
281 and libref="&libref"
282 and dsn="&ds";
283
284%mp_abort(
285 iftrue=(%mf_verifymacvars(mpelocapprovals orig_libds)=0)
286 ,mac=&_program
287 ,msg=%str(Missing: mpelocapprovals orig_libds)
288)
289
290/* get dataset from approvals location (has same name as load_ref) */
291%let tmplib=%mf_getuniquelibref();
292libname &tmplib "&mpelocapprovals/&LOAD_REF";
293data STAGING_DS;
294 set &tmplib..&LOAD_REF;
295run;
296
297%mp_abort(iftrue= (&syscc ne 0)
298 ,mac=&_program..sas
299 ,msg=%str(syscc=&syscc before preapprove)
300)
301
302%dc_assignlib(WRITE,&libref)
303
304/* run pre-approve hook - occurs both BEFORE _and_ AFTER the diff */
305%mpe_runhook(PRE_APPROVE_HOOK)
306
307%mp_abort(iftrue= (&syscc ne 0)
308 ,mac=&_program..sas
309 ,msg=%str(syscc=&syscc after preapprove)
310)
311
312%if &num_of_approvals_remaining>1 and &action=APPROVE_TABLE %then %do;
313
314 /* append to mpe_review table */
315 %let apprno=%eval(&num_of_approvals_required-&num_of_approvals_remaining+1);
316 data work.append_review;
317 if 0 then set &mpelib..mpe_review;
318 TABLE_ID="&LOAD_REF";
319 BASE_TABLE="&orig_libds";
320 REVIEW_STATUS_ID="APPROVED";
321 REVIEWED_BY_NM="&user";
322 REVIEWED_ON_DTTM=&sastime;
323 REVIEW_REASON_TXT="APPROVAL &apprno of &num_of_approvals_required";
324 output;
325 stop;
326 run;
327 %mp_lockanytable(LOCK,
328 lib=&mpelib,ds=mpe_review,ref=%str(&LOAD_REF Approval),
329 ctl_ds=&mpelib..mpe_lockanytable
330 )
331 proc append base=&mpelib..mpe_review data=work.append_review;
332 run;
333 %mp_lockanytable(UNLOCK,
334 lib=&mpelib,ds=mpe_review,
335 ctl_ds=&mpelib..mpe_lockanytable
336 )
337
338 /* update mpe_submit table */
339 %mp_lockanytable(LOCK,
340 lib=&mpelib,ds=mpe_submit,ref=%str(&LOAD_REF Approval),
341 ctl_ds=&mpelib..mpe_lockanytable
342 )
343 proc sql;
344 update &mpelib..mpe_submit
345 set num_of_approvals_remaining=&num_of_approvals_remaining-1,
346 reviewed_by_nm="&user",
347 reviewed_on_dttm=&sastime
348 where table_id="&LOAD_REF";
349 %mp_lockanytable(UNLOCK,
350 lib=&mpelib,ds=mpe_submit,
351 ctl_ds=&mpelib..mpe_lockanytable
352 )
353
354 data apReqd;
355 AUTHORISED=1;
356 ALREADY_UPDATED=0;
357 ALREADY_UPDATED_DTTM=.;
358 set approve1; /* js will test for NUM_OF_APPROVALS_REQUIRED */
359 run;
360 %removecolsfromwork(___TMP___MD5)
361 %webout(OPEN)
362 %webout(OBJ,apReqd);
363 %webout(CLOSE)
364 %return;
365
366%end;
367
368%mp_abort(iftrue= (&syscc ne 0)
369 ,mac=&_program..sas
370 ,msg=%str(syscc=&syscc entering TARGETLOADER)
371)
372%mpe_targetloader(libds=&orig_libds
373 ,now= &sastime
374 ,etlsource=&LOAD_REF
375 ,STAGING_DS=STAGING_DS
376 ,dclib=&mpelib
377%if &action=APPROVE_TABLE %then %do;
378 ,LOADTARGET=YES
379%end;
380%else %do;
381 ,LOADTARGET=NO
382%end;
383 ,dc_dttmtfmt=&dc_dttmtfmt.
384)
385
386
387%if %mf_getattrn(STAGING_DS,NLOBS)=0 %then %do;
388 /* empty dataset! */
389 data out;
390 set STAGING_DS;
391 run;
392 %return;
393%end;
394
395%mp_abort(iftrue= (&syscc ne 0)
396 ,mac=&_program..sas
397 ,msg=%str(syscc=&syscc entering SHOWDIFFS)
398)
399%if &action=SHOW_DIFFS %then %do;
400
401 /**
402 * Now prepare the SHOW DIFFS (approve) screen
403 */
404
405 /*To create the CURRENT diffs, we compare with the ACTUAL data. But first
406 need to find out what version TIME to query it for.. */
407 proc sql noprint;
408 select max(processed_dttm)-1 format=datetime19. into: tstamp
409 from &mpelib..mpe_dataloads
410 where libref="&libref" and dsn="&ds" and ETLSOURCE="&LOAD_REF";
411 quit;
412 %if &tstamp=. %then %let tstamp=%sysfunc(datetime(),datetime19.);
413
414 /**
415 * now create the DIFFS dataset
416 * If using a database, then utilise pass through!
417 * Create a temporary table inside the database for joins..
418 */
419 options mprint;
420 %let engine_type=%mf_getEngine(%scan(&libds,1,.));
421 %put &libds engine type = &engine_type;
422 %local inner_table ;
423 %if &engine_type=OLEDB %then %do;
424 /* generate a unique ID for the temporary table */
425 data _null_;
426 call symputx('UNIQUE_REF'
427 ,cats(round(datetime(),1)
428 ,'_'
429 ,round(ranuni(0)*100000,1)
430 )
431 ,'l'
432 );
433 run;
434 %let inner_table=&libref.."##DIFF_&UNIQUE_REF"n;
435 proc sql;
436 create table &inner_table as
437 select * from work.outds_mod;
438 %end;
439 %else %let inner_table=work.outds_mod;
440 proc sql;
441 create view work.originals2 as
442 select b.*
443 from &inner_table a
444 inner join &libds
445 %if &loadtype=BITEMPORAL or &loadtype=TXTEMPORAL %then %do;
446 (where=("&tstamp"dt < &VAR_TXTO))
447 %end;
448 b
449 on 1
450 %do idx_pk=1 %to %sysfunc(countw(&buskey));
451 %let idx_val=%scan(&buskey,&idx_pk);
452 and a.&idx_val=b.&idx_val
453 %end;
454 order by %mf_getquotedstr(in_str=&buskey,dlm=%str(,),quote=)
455 ;
456
457 create view bitemp5c_updates2 as
458 select * from work.outds_mod
459 order by %mf_getquotedstr(in_str=&buskey,dlm=%str(,),quote=)
460 ;
461
462 data; set &libds;stop;run;
463 %let emptybasetable=&syslast;
464
465 options varlenchk=nowarn; /* for small numerics (<8) */
466 %quickmacro(work.outds_del,deleted)
467 %quickmacro(work.outds_add,new)
468 %quickmacro(bitemp5c_updates2,updates)
469 %quickmacro(originals2,originals)
470
471 %mp_abort(iftrue= (&syscc ne 0)
472 ,mac=&_program..sas
473 ,msg=%str(syscc=&syscc in quickmacro)
474 )
475
476 /* extract colnames for md5 creation / change tracking */
477 proc contents noprint data=work.updates
478 out=cols (keep=name type length varnum format);
479 run;
480 proc sort data=cols out=cols(drop=varnum); by varnum;run;
481 data cols; set cols; name=upcase(name);run;
482 %let tempDIFFS_CSV=tempDiffs_%trim(
483 %sysfunc(datetime(),flatdate.)).csv;
484
485 /**
486 * Store temp tables so we have a record of diffs
487 * do not change this libname or table name as it is used in some
488 * post approve hooks
489 */
490
491 data TEMPDIFFS (compress=no) /* for realistic file size */;
492 length _____status $10;
493 set work.deleted (in=_____del)
494 work.new(in=_____new)
495 work.updates (in=_____upd)
496 work.originals2 (in=_____orig);
497 if _____del then _____status='DELETED ';
498 else if _____new then _____status='NEW';
499 else if _____upd then _____status='UPDATED';
500 else if _____orig then _____status='ORIGINAL';
501 run;
502 proc export data=TEMPDIFFS dbms=csv replace
503 outfile="&mpelocapprovals/&LOAD_REF/&tempDIFFS_CSV" ;
504 run;
505 proc sql noprint;
506 select filesize format=sizekmg10.1, filesize as filesize_raw
507 into: filesize,:filesize_raw
508 from dictionary.tables
509 where libname='WORK' and memtype='DATA' and memname='TEMPDIFFS';
510
511 data params;
512 set approve1;
513 DIFFS_CSV="&tempDIFFS_CSV";
514 FILESIZE="&filesize";
515 FILESIZE_RAW=&filesize_raw;
516 if %mf_nobs(work.originals)>&maxdiff
517 or %mf_nobs(work.new)>&maxdiff
518 or %mf_nobs(work.deleted)>&maxdiff
519 or %mf_nobs(work.updates)>&maxdiff
520 then TRUNCATED="YES";
521 else TRUNCATED="NO";
522
523 NUM_ADDED=%mf_getattrn(work.new,NLOBS);
524 NUM_DELETED=%mf_getattrn(work.deleted,NLOBS);
525 NUM_UPDATED=%mf_getattrn(work.updates,NLOBS);
526 SUBMITTED_ON=put(submitted_on_dttm,datetime19.);
527 %if %mf_getattrn(work.authAPP,NLOBS)>0 %then %do;
528 ISAPPROVER='YES';
529 %end;
530 %else %do;
531 ISAPPROVER='NO';
532 %end;
533 run;
534
535 /*
536 * The PRE_APPROVE_HOOK may have applied custom formats to the staged table.
537 * To ensure consistency in the DIFF screen, we should apply the same formats
538 * to the base table. Limit rows at the same time.
539 */
540 data work.originals;
541 if 0 then set deleted new updates;
542 set work.originals;
543 if _n_>&maxdiff then stop;
544 run;
545
546 /* get additional submits against the same base table */
547 proc sort data=&mpelib..mpe_submit(where=(
548 submit_status_cd='SUBMITTED'
549 and cats(base_lib,'.',base_ds)="&orig_libds"
550 and table_id ne "&LOAD_REF"
551 )) out=submits;
552 by descending submitted_on_dttm;
553 run;
554
555 /* filter last 10 */
556 data submits;
557 set submits;
558 if _n_>10 then stop;
559 run;
560
561 %mp_abort(iftrue= (&syscc ne 0)
562 ,mac=&_program..sas
563 ,msg=%str(syscc=&syscc SHOWDIFFS prior to streamout)
564 )
565
566 %removecolsfromwork(___TMP___MD5)
567 %webout(OPEN)
568 %webout(OBJ,params)
569 %webout(OBJ,cols)
570 %webout(OBJ,submits)
571 %webout(OBJ,deleted,fmt=N,missing=STRING,maxobs=&maxdiff)
572 %webout(OBJ,new,fmt=N,missing=STRING,maxobs=&maxdiff)
573 %webout(OBJ,updates,fmt=N,missing=STRING,maxobs=&maxdiff)
574 %webout(OBJ,ORIGINALS,fmt=N,missing=STRING)
575 /* need same for formatted view */
576 %webout(OBJ,deleted,dslabel=fmt_deleted,fmt=Y,missing=STRING,maxobs=&maxdiff)
577 %webout(OBJ,new,dslabel=fmt_new,fmt=Y,missing=STRING,maxobs=&maxdiff)
578 %webout(OBJ,updates,dslabel=fmt_updates,fmt=Y,missing=STRING,maxobs=&maxdiff)
579 %webout(OBJ,originals,dslabel=fmt_ORIGINALS,fmt=Y,missing=STRING)
580 %webout(CLOSE)
581
582 %if &engine_type=OLEDB %then %do;
583 proc sql; /* needs to be dropped AFTER view execution */
584 drop table &inner_table;
585 %end;
586
587 %return;
588%end;
589
590
591%if &action=APPROVE_TABLE %then %do;
592 %approve:
593 /**
594 * store temp tables so we have a record of diffs
595 * do not change this libname or table name as it is used in some
596 * post approve hooks
597 * for REPLACE loads, temp tables not made, so make them
598 */
599 %if &LOADTYPE=REPLACE %then %do;
600 data work.outds_add; run;
601 data work.outds_mod; run;
602 data work.outds_del; run;
603 %end;
604 libname approve "&mpelocapprovals/&LOAD_REF";
605 data; set &libds;stop;run;
606 %let emptybasetable=&syslast;
607 data approve.ActualDiffs;
608 length _____STATUS_____ $10;
609 if 0 then set &emptybasetable;
610 set work.outds_del (in=_____del)
611 work.outds_add (in=_____new)
612 work.outds_mod (in=_____upd);
613 if _____del then _____STATUS_____='DELETED';
614 else if _____new then _____STATUS_____='NEW';
615 else if _____upd then _____STATUS_____='UPDATED';
616
617 %if %mf_existvar(&libds,&var_txfrom) %then %do;
618 drop &var_txfrom &var_txto;
619 %end;
620 %if %mf_existvar(&libds,&VAR_PROCESSED) %then %do;
621 drop &VAR_PROCESSED;
622 %end;
623 run;
624
625 proc export data=approve.ActualDiffs
626 outfile="&mpelocapprovals/&LOAD_REF/ActualDiffs.csv"
627 dbms=csv
628 replace;
629 run;
630
631 /* update the control table to show table as approved */
632 /* append to mpe_review table */
633 %let apprno=%eval(&num_of_approvals_required-&num_of_approvals_remaining+1);
634 data work.append_review;
635 if 0 then set &mpelib..mpe_review;
636 TABLE_ID="&LOAD_REF";
637 BASE_TABLE="&orig_libds";
638 REVIEW_STATUS_ID="APPROVED";
639 REVIEWED_BY_NM="&user";
640 REVIEWED_ON_DTTM=&sastime;
641 REVIEW_REASON_TXT="APPROVAL &apprno of &num_of_approvals_required";
642 output;
643 stop;
644 run;
645 %mp_lockanytable(LOCK,
646 lib=&mpelib,ds=mpe_review,ref=%str(&LOAD_REF Approval),
647 ctl_ds=&mpelib..mpe_lockanytable
648 )
649 proc append base=&mpelib..mpe_review data=work.append_review;
650 run;
651 %mp_lockanytable(UNLOCK,
652 lib=&mpelib,ds=mpe_review,
653 ctl_ds=&mpelib..mpe_lockanytable
654 )
655
656 /* update mpe_submit table */
657 %mp_lockanytable(LOCK,
658 lib=&mpelib,ds=mpe_submit,ref=%str(&LOAD_REF Approval in auditors/postdata),
659 ctl_ds=&mpelib..mpe_lockanytable
660 )
661 proc sql;
662 update &mpelib..mpe_submit
663 set submit_status_cd='APPROVED',
664 num_of_approvals_remaining=&num_of_approvals_remaining-1,
665 reviewed_by_nm="&user",
666 reviewed_on_dttm=&sastime
667 where table_id="&LOAD_REF";
668 %mp_lockanytable(UNLOCK,
669 lib=&mpelib,ds=mpe_submit,
670 ctl_ds=&mpelib..mpe_lockanytable
671 )
672
673 /* save table to disk (if viya + cas) */
674 %dc_cassave(&libds)
675
676 /* run post-approve hook */
677 %mpe_runhook(POST_APPROVE_HOOK)
678
679 data apPARAMS;
680 AUTHORISED=1;
681 ALREADY_UPDATED=0;
682 ALREADY_UPDATED_DTTM=.;
683 DIFFTIME="&difftime";
684 if &syscc=0 then RESPONSE='SUCCESS!';
685 else response="SYSCC=&syscc.";
686 run;
687
688 %mp_abort(iftrue= (&syscc ne 0)
689 ,mac=&_program 582
690 ,msg=%superq(msg)
691 )
692
693 %mpe_alerts(alert_event=APPROVED
694 , alert_lib=&libref
695 , alert_ds=&ds
696 , dsid=&LOAD_REF
697 )
698
699 %removecolsfromwork(___TMP___MD5)
700 %webout(OPEN)
701 %webout(OBJ,apPARAMS)
702 %webout(CLOSE)
703 %return;
704%end;
705%mend postdata;
706
707%postdata()
708
709%mp_abort(mode=INCLUDE)
710
711%mp_abort(iftrue= (&is_err=1)
712 ,mac=&_program
713 ,msg=%superq(err_msg)
714)
715
716%mpeterm()