Odyssey
LoanGeneratorMapper.php
1 <?php
2 /**
3  * @copyright HomeCu 05/2019
4  *
5  * Maps and array of CSV test data to the DB field data. There is no direct 1:1 mapping
6  * we can build easily. We have to go into the JSON in lnnappschemadetail->fieldattr
7  * and look for a match on "responsetablefield" or "fieldcorename" to correctly
8  * map CSV fields to DB fields.
9  *
10  * Injects into LoanDataGenerator class and probably has no other useful
11  * application, but **does** allow LoanDataGenerator to utilize a
12  * different mapper if it applies.
13  */
15 {
16 
17  /** @var string $cu - loans currently only work in dev for CRUISECU */
18  protected $cu = 'SCRUBSCU';
19  /**
20  * LoanGeneratorMapper constructor.
21  * @param string $cu
22  * @return void
23  */
24  public function __construct($cu = '') {
25 
26  if (! empty($cu)) {
27  $this->cu = $cu;
28  }
29  }
30 
31  /**
32  * Using the master template, create the template for this loan.
33  * @param int $loan_id
34  * @param array $map (of detail schema template)
35  * @return array
36  */
37  public function CreateDetailTemplateMap($loan_id, $map) {
38 
39  $count = count($map);
40 
41  for ($i = 0; $i < $count; $i++) {
42  if (isset($map[$i]['detailid'])) {
43  unset($map[$i]['detailid']);
44  }
45 
46  $map[$i]['loanid'] = $loan_id;
47  }
48 
49  return [
50  'lnappschemadetail' => $map
51  ];
52  }
53 
54 
55  /**
56  * Map the lnappschemamaster table.
57  * @param array $row
58  * @return array
59  * @throws Exception
60  */
61  public function masterSchemaMap($row) {
62 
63  $dt = new DateTime();
64  return [
65  'lnappschemamaster' => [
66  [
67  'cu' => $this->cu,
68  'loantitle' => "{$row['b_fname']} {$row['b_lname']} {$row['loan_purpose']} Loan",
69  'loandisclosure_fragment' => '',
70  'lastmodified' => $dt->format('Y-m-d')
71  ]
72  ]
73  ];
74  }
75 
76  /**
77  * Compile three sample challenge answers all this the same answer
78  * @param string $test_credentials
79  * @param int $user_id
80  * @return array
81  */
82  public function mapRandomQuestionResponses($user_id, $test_credentials) {
83 
84  $insert = [];
85  $qids = [rand(50, 65)];
86 
87  while (count($qids) < 3) {
88  $qids = $this->AddToArray($qids);
89  }
90 
91  foreach ($qids as $id) {
92  $insert[] = [
93  'userid' => $user_id,
94  'questid' => $id,
95  'user_answer' => $test_credentials
96  ];
97  }
98 
99  return ['lnappuser_questselect' => $insert];
100  }
101 
102  /**
103  * Helper for above.
104  * @param array $arr
105  * @return array
106  */
107  protected function AddToArray($arr) {
108 
109  $id = rand(50, 65);
110 
111  if (! in_array($id, $arr)) {
112  array_push($arr, $id);
113  }
114  return $arr;
115  }
116 
117 
118  /**
119  * map the user data
120  * @param array $row
121  * @param string $test_credentials
122  * @return array
123  */
124  public function MapUserData($row, $test_credentials) {
125 
126  return [
127  'lnappuser' => [
128  [
129  'email' => $row['b_email'],
130  'pwd' => password_hash($test_credentials, PASSWORD_DEFAULT),
131  'allow_e_comm' => 0,
132  'cu' => $this->cu,
133  'confidenceword' => $test_credentials,
134  'failedloginattempts' => 0,
135  'challenge_quest_id' => -1,
136  'userlogintype' => null,
137  'banking_user_id' => 0,
138  'session_account' => null
139  ]
140  ]
141  ];
142  }
143  /**
144  * map the loan data
145  * @param int $user_id
146  * @param int $loan_id
147  * @param array $row
148  * @param array $data = entire data loan set
149  * @throws Exception
150  * @return array
151  */
152  public function MapUserLoan($user_id, $loan_id, $row, $data) {
153 
154  $dt = new DateTime();
155  $date = $dt->format('Y-m-d');
156 
157  // @TODO initially wanted to build this as one call, but didn't work out, de-nest these
158  return [
159  'lnappuserresponse' => [
160  [
161  'userid' => $user_id,
162  'loanid' => $loan_id,
163  'respstatus' => 0,
164  'respcomments' => '',
165  'respcoreloanappid' => -1,
166  'respstarton' => $date,
167  'respsubmiton' => null,
168  'respmodifiedon' => $date,
169  'respfname' => $row['b_fname'],
170  'resplname' => $row['b_lname'],
171  'respmname' => $row['b_mname'],
172  'respssn' => $row['b_ssn'], // SOOOOO bad.
173  'respdob' => $row['b_dob'],
174  'respmember' => '',
175  'respphone' => '',
176  'respapplication' => $this->CreateJsonApp( $row, $data),
177  'respstatusdesc' => null,
178  'respamt' => $row['loan_amount'],
179  'resplastinquire' => null
180  ]
181  ]
182  ];
183  }
184 
185  /**
186  * Find the **correct** detail id in the schema template for this app and create the JSON
187  * array that will go into the field respapplication.
188  * @param array $row
189  * @param array $data = entire data set for creation of JSON.
190  * @return string
191  */
192  protected function CreateJsonApp($row, $data) {
193 
194  $json_map = $this->CreateJsonMap($row, $data['data']);
195 
196  // Using this map, create an array with proper field->value associations
197  // Could do `return json_encode($this->MapCsvToJsonArray($row, $json_map))`
198  // Left the var set do we can just output $mapped on it's own in debug
199  $mapped = $this->MapCsvToJsonArray($row, $json_map);
200 
201  // return it json encoded for storing in the app record.
202  return json_encode($mapped);
203  }
204 
205 
206  /**
207  * Here we map the actual data to the record ID found and set in createJsonMap(). So what we have done is
208  * 1) Find the detailid in each field of this record's schemadetail by parsing the JSON of fieldattr
209  * in template, in the example below, 1234
210  * 2) Created an array associating our "json field names" with the CSV names as in
211  * 'productname' => 'formfield_1234'
212  * 4) Below we create the "finished" array with values associated with "json field names" as in
213  * 'formfield_1234' => 'HomeCu'
214  * 5) "Never time to do it right . . . ."
215  * @param array $row
216  * @param array $json_map
217  * @return array
218  */
219  protected function MapCsvToJsonArray($row, $json_map) {
220 
221  $data = [];
222 
223  foreach ($row as $key => $value) {
224  if (array_key_exists($key, $json_map)) {
225  $data[$json_map[$key]] = $value;
226  }
227  }
228 
229  return $data;
230  }
231 
232  /**
233  * Here we attempt to map to the field in the detail template.
234  * @param array $row
235  * @param array $tpl
236  * @return array
237  */
238  protected function CreateJsonMap($row = [], $tpl = []) {
239 
240  $map = [];
241 
242  foreach ($row as $field => $value) {
243 
244  $id = $this->FindFieldId($field, $tpl);
245 
246  // Not logging these to the errors array. It's not helpful and it
247  // just means some fields won't be in the JSON
248  if (! $id) {
249  continue;
250  }
251 
252  $map[$field] = 'formfield_' . $id;
253  }
254 
255  return $map;
256  }
257 
258  /**
259  * Attempt to locate the matching array key "responsetablefield" or "fieldcorename"
260  * If it matches the mapping of one or the other, return the record ID.
261  * @param string $field
262  * @param array $tpl
263  * @return int|null
264  */
265  protected function FindFieldId($field, $tpl) {
266 
267  foreach ($tpl as $arr) {
268 
269  $field_attr = $this->DecodeFieldAttr($arr);
270 
271  if (empty($field_attr)) {
272  continue;
273  }
274 
275  if (! empty($this->FindFieldIdentifier($field, $field_attr))) {
276  return $arr['detailid'];
277  break;
278  }
279  }
280 
281  return null;
282  }
283 
284  /**
285  * Parse fieldattr and return the array. Should never fail but . . .
286  * @param array $field_arr
287  * @return array|null
288  */
289  protected function DecodeFieldAttr($field_arr = []) {
290 
291  if (empty($field_arr)) {
292  return null;
293  }
294 
295  if (! (
296  array_key_exists('fieldattr', $field_arr) &&
297  ! empty($field_arr['fieldattr'])
298  )) {
299  return null;
300  }
301 
302  return json_decode($field_arr['fieldattr'], 1);
303 
304  }
305 
306  /**
307  * Map the CSV field $field to either the local response table field or core field name.
308  * This will tell us which "schema record id" to use in the JSON.
309  * @param $field
310  * @param $field_attr
311  * @return string|null
312  */
313  protected function FindFieldIdentifier($field, $field_attr) {
314 
315  $local = (array_key_exists('responsetablefield', $field_attr))? $field_attr['responsetablefield'] : null;
316  $core = (array_key_exists('fieldcorename', $field_attr))? $field_attr['fieldcorename'] : null;
317 
318  if (! ($local || $core)) {
319  return null;
320  }
321 
322  $arr = [
323  'product' => ['local' => null, 'core' => 'productname'],
324  'loan_purpose' => ['local' => null, 'core' => 'lnpurpose'],
325  'loan_type' => ['local' => null, 'core' => 'loantype'],
326  // No mapping for this one, I guess let it return null
327  'app_started' => ['local' => null, 'core' => null],
328  'loan_amount' => ['local' => 'respamt', 'core' => 'amtreqd'],
329  'individual_joint' => ['local' => null, 'core' => 'indvjoint'],
330  'disab_ins' => ['local' => null, 'core' => 'appcdioption'],
331  'credit_ins' => ['local' => null, 'core' => 'appclioption'],
332  'b_fname' => ['local' => 'respfname', 'core' => 'dms_appfname'],
333  'b_mname' => ['local' => 'respmname', 'core' => 'dms_appmname'],
334  'b_lname' => ['local' => 'resplname', 'core' => 'dms_applname'],
335  'b_ssn' => ['local' => 'respssn', 'core' => 'dms_apptin'],
336  'b_account' => ['local' => 'respmember', 'core' => 'dms_accountnumber'],
337  'b_dob' => ['local' => 'respdob', 'core' => 'appbirthdate'],
338  'b_email' => ['local' => null, 'core' => 'appemail'],
339  'b_home_ph' => ['local' => null, 'core' => 'apphomephone'],
340  'b_work' => ['local' => null, 'core' => 'appworkphone'],
341  'b_cell' => ['local' => null, 'core' => 'appcellphone'],
342  'b_years_residence' => ['local' => null, 'core' => 'appyearsataddress'],
343  'b_address' => ['local' => null, 'core' => 'appaddr'],
344  'b_city' => ['local' => null, 'core' => 'dms_appcity'],
345  'b_state' => ['local' => null, 'core' => 'dms_appst'],
346  'b_zip' => ['local' => null, 'core' => 'dms_appzip'],
347  'b_employer' => ['local' => null, 'core' => 'appemployer'],
348  'b_monthly_income' => ['local' => null, 'core' => 'appmonthincome'],
349  'b_emp_status' => ['local' => null, 'core' => 'appemploystatus'],
350  'b_job_title' => ['local' => null, 'core' => 'appjobtitle'],
351  'b_emp_started_on' => ['local' => null, 'core' => 'appjobstartdate'],
352  'b_income_other' => ['local' => null, 'core' => 'appotherincome'],
353  'b_inc_other_src' => ['local' => null, 'core' => 'appotherincomesource'],
354  'b_own_rent' => ['local' => null, 'core' => 'apphousingtype'],
355  'b_monthly_housing' => ['local' => null, 'core' => 'apphousingpmt'],
356  // Child support left out "fieldcorename":"appchildsupportdesc" "fieldcorename":"appchildsupportpmt"
357  'b_ref_fname' => ['local' => null, 'core' => 'dms_appreffname'],
358  'b_ref_lname' => ['local' => null, 'core' => 'dms_appreflname'],
359  'b_ref_addr' => ['local' => null, 'core' => 'apprefaddr'],
360  // What's with the "1" in these three ONLY?
361  'b_ref_city' => ['local' => null, 'core' => 'dms_appref1city'],
362  'b_ref_state' => ['local' => null, 'core' => 'dms_appref1st'],
363  'b_ref_zip' => ['local' => null, 'core' => 'dms_appref1zip'],
364  'b_ref_phone' => ['local' => null, 'core' => 'apprefphone'],
365  'b_ref_relation' => ['local' => null, 'core' => 'appreftype'],
366  'c_fname' => ['local' => null, 'core' => 'dms_coappfname'],
367  'c_mname' => ['local' => null, 'core' => 'dms_coappmname'],
368  'c_lname' => ['local' => null, 'core' => 'dms_coapplname'],
369  'c_ssn' => ['local' => null, 'core' => 'coapptin'],
370  // No mapping for this one
371  'c_account' => ['local' => null, 'core' => null],
372  'c_dob' => ['local' => null, 'core' => 'coappbirthdate'],
373  'c_email' => ['local' => null, 'core' => 'coappemail'],
374  'c_home_ph' => ['local' => null, 'core' => 'coapphomephone'],
375  'c_work' => ['local' => null, 'core' => 'coappworkphone'],
376  'c_cell' => ['local' => null, 'core' => 'coappcellphone'],
377  'c_years_residence' => ['local' => null, 'core' => 'coappyearsataddress'],
378  'c_address' => ['local' => null, 'core' => 'coappaddr'],
379  'c_city' => ['local' => null, 'core' => 'dms_coappaddrcity'],
380  'c_state' => ['local' => null, 'core' => 'dms_coappaddrst'],
381  'c_zip' => ['local' => null, 'core' => 'dms_coappaddrzip'],
382  'c_employer' => ['local' => null, 'core' => 'coappemployer'],
383  'c_monthly_income' => ['local' => null, 'core' => 'coappmonthincome'],
384  // No mapping for this one
385  'c_emp_status' => ['local' => null, 'core' => null],
386  'c_job_title' => ['local' => null, 'core' => 'coappjobtitle'],
387  'c_emp_started_on' => ['local' => null, 'core' => 'coappjobstartdate'],
388  'c_income_other' => ['local' => null, 'core' => 'coappotherincome'],
389  'c_inc_other_src' => ['local' => null, 'core' => 'coappotherincomesource'],
390  'c_own_rent' => ['local' => null, 'core' => 'coapphousingtype'],
391  // Why is there mortgage desc. here and not for main? Leaving both out.
392  'c_monthly_housing' => ['local' => null, 'core' => 'coapphousingpmt'],
393  // Child support left out.
394  'c_ref_fname' => ['local' => null, 'core' => 'dms_coappreffname'],
395  'c_ref_lname' => ['local' => null, 'core' =>'dms_coappreflname'],
396  'c_ref_addr' => ['local' => null, 'core' => 'coapprefaddr'],
397  'c_ref_city' => ['local' => null, 'core' => 'dms_coappref1city'],
398  'c_ref_state' => ['local' => null, 'core' => 'dms_coappref1st'],
399  'c_ref_zip' => ['local' => null, 'core' => 'dms_coappref1zip'],
400  'c_ref_phone' => ['local' => null, 'core' => 'coapprefphone'],
401  'c_ref_relation' => ['local' => null, 'core' => 'coappreftype']
402  ];
403 
404  // These return values aren't used for anything but debugging and to test for
405  // an empty response or not, to confirm we have a mapping.
406  if (array_key_exists($field, $arr)) {
407  $map = $arr[$field];
408  if (! is_null($local) && ($map['local'] == $local)) {
409  return 'local';
410  }
411  if (! is_null($core) && ($map['core'] == $core)) {
412  return 'core';
413  }
414  }
415 
416  return null;
417 
418  }
419 
420 }
mapRandomQuestionResponses($user_id, $test_credentials)
MapUserData($row, $test_credentials)
FindFieldIdentifier($field, $field_attr)
CreateJsonMap($row=[], $tpl=[])
DecodeFieldAttr($field_arr=[])
MapUserLoan($user_id, $loan_id, $row, $data)
CreateDetailTemplateMap($loan_id, $map)
MapCsvToJsonArray($row, $json_map)