@ironcode/vas-lib 3.0.0-alpha.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/cjs/lib/entity/vas-form.model.js +1 -1
  2. package/cjs/lib/entity/vas-form.model.js.map +1 -1
  3. package/cjs/lib/entity/vas-job.dto.d.ts +3 -0
  4. package/cjs/lib/entity/vas-job.dto.d.ts.map +1 -1
  5. package/cjs/lib/entity/vas-job.dto.js.map +1 -1
  6. package/cjs/lib/entity/vas-job.model.d.ts +7 -2
  7. package/cjs/lib/entity/vas-job.model.d.ts.map +1 -1
  8. package/cjs/lib/entity/vas-job.model.js +150 -21
  9. package/cjs/lib/entity/vas-job.model.js.map +1 -1
  10. package/cjs/lib/model/estimate-control/estimate-item.dto.d.ts +1 -0
  11. package/cjs/lib/model/estimate-control/estimate-item.dto.d.ts.map +1 -1
  12. package/cjs/lib/model/estimate-control/estimate-item.dto.js.map +1 -1
  13. package/cjs/lib/model/estimate-control/estimate-item.model.d.ts +3 -2
  14. package/cjs/lib/model/estimate-control/estimate-item.model.d.ts.map +1 -1
  15. package/cjs/lib/model/estimate-control/estimate-item.model.js +13 -6
  16. package/cjs/lib/model/estimate-control/estimate-item.model.js.map +1 -1
  17. package/cjs/lib/model/estimate-control/estimate-source.d.ts +2 -0
  18. package/cjs/lib/model/estimate-control/estimate-source.d.ts.map +1 -0
  19. package/cjs/lib/model/estimate-control/estimate-source.js +3 -0
  20. package/cjs/lib/model/estimate-control/estimate-source.js.map +1 -0
  21. package/cjs/lib/model/estimate-control/estimate.dto.d.ts +2 -1
  22. package/cjs/lib/model/estimate-control/estimate.dto.d.ts.map +1 -1
  23. package/cjs/lib/model/estimate-control/estimate.dto.js.map +1 -1
  24. package/cjs/lib/model/estimate-control/estimate.model.d.ts +2 -3
  25. package/cjs/lib/model/estimate-control/estimate.model.d.ts.map +1 -1
  26. package/cjs/lib/model/estimate-control/estimate.model.js +31 -18
  27. package/cjs/lib/model/estimate-control/estimate.model.js.map +1 -1
  28. package/cjs/lib/model/estimate-control/index.d.ts +1 -0
  29. package/cjs/lib/model/estimate-control/index.d.ts.map +1 -1
  30. package/cjs/lib/model/estimate-control/index.js.map +1 -1
  31. package/fesm2022/ironcode-vas-lib.mjs +241 -87
  32. package/fesm2022/ironcode-vas-lib.mjs.map +1 -1
  33. package/lib/entity/vas-job.dto.d.ts +3 -0
  34. package/lib/entity/vas-job.model.d.ts +7 -2
  35. package/lib/model/estimate-control/estimate-item.dto.d.ts +1 -0
  36. package/lib/model/estimate-control/estimate-item.model.d.ts +3 -2
  37. package/lib/model/estimate-control/estimate-source.d.ts +1 -0
  38. package/lib/model/estimate-control/estimate.dto.d.ts +2 -1
  39. package/lib/model/estimate-control/estimate.model.d.ts +2 -3
  40. package/lib/model/estimate-control/index.d.ts +1 -0
  41. package/package.json +1 -1
@@ -2245,7 +2245,7 @@ class VasFormModel extends VasRestrictedAccountObjectModel {
2245
2245
  if (control.controlTypeName !== 'camera') {
2246
2246
  return;
2247
2247
  }
2248
- paths.push([group.name, control.safeName]);
2248
+ paths.push(control.name.split('.'));
2249
2249
  });
2250
2250
  });
2251
2251
  return paths;
@@ -3346,7 +3346,8 @@ class EstimateItemModel {
3346
3346
  workCategory;
3347
3347
  costCategory;
3348
3348
  comment;
3349
- constructor(id, description, type, quantity, quantityAdjusted, units, unitsAdjusted, price, priceAdjusted, workCategory, costCategory, comment) {
3349
+ vatExcluded;
3350
+ constructor(id, description, type, quantity, quantityAdjusted, units, unitsAdjusted, price, priceAdjusted, workCategory, costCategory, comment, vatExcluded) {
3350
3351
  this.id = id;
3351
3352
  this.description = description;
3352
3353
  this.type = type;
@@ -3359,17 +3360,21 @@ class EstimateItemModel {
3359
3360
  this.workCategory = workCategory;
3360
3361
  this.costCategory = costCategory;
3361
3362
  this.comment = comment;
3363
+ this.vatExcluded = vatExcluded;
3362
3364
  }
3363
3365
  getTotalUnits(adjusted = false) {
3364
3366
  return adjusted ?
3365
3367
  b$2(this.quantityAdjusted || '0').mul(this.unitsAdjusted || '0').toFixed(2) :
3366
3368
  b$2(this.quantity || '0').mul(this.units || '0').toFixed(2);
3367
3369
  }
3368
- getLineValue(labourRate = '1', timeBasis = '1', adjusted = false) {
3370
+ getLineValue(labourRate = '1', timeBasis = '1', adjusted = false, vatExcluded) {
3369
3371
  const cat = this.costCategory || 'none';
3370
3372
  if (this.workCategory === 'removed') {
3371
3373
  return '0';
3372
3374
  }
3375
+ if (vatExcluded !== undefined && this.vatExcluded !== vatExcluded) {
3376
+ return '0';
3377
+ }
3373
3378
  const units = (adjusted ? this.unitsAdjusted : this.units) || 0;
3374
3379
  const quantity = (adjusted ? this.quantityAdjusted : this.quantity) || 0;
3375
3380
  const price = (adjusted ? this.priceAdjusted : this.price) || '';
@@ -3394,7 +3399,9 @@ class EstimateItemModel {
3394
3399
  .mul(quantity || '0')
3395
3400
  .toFixed(2);
3396
3401
  }
3397
- case 'specialist': {
3402
+ case 'specialist':
3403
+ case 'pl':
3404
+ case 'other': {
3398
3405
  return b$2(price || '0')
3399
3406
  .mul(quantity || '0')
3400
3407
  .toFixed(2);
@@ -3422,14 +3429,15 @@ class EstimateItemModel {
3422
3429
  priceAdjusted: this.priceAdjusted,
3423
3430
  workCategory: this.workCategory,
3424
3431
  costCategory: this.costCategory,
3425
- comment: this.comment
3432
+ comment: this.comment,
3433
+ vatExcluded: this.vatExcluded
3426
3434
  };
3427
3435
  }
3428
3436
  static create() {
3429
- return new EstimateItemModel(v4(), '', '', 1, 1, 0, 0, '', '', 'none', 'none', '');
3437
+ return new EstimateItemModel(v4(), '', '', 1, 1, 0, 0, '', '', 'none', 'none', '', false);
3430
3438
  }
3431
3439
  static fromDto(dto) {
3432
- return new EstimateItemModel(dto.id || v4(), dto.description || '', dto.type || '', dto.quantity || 0, dto.quantityAdjusted || 0, dto.units || 0, dto.unitsAdjusted || 0, dto.price || '', dto.priceAdjusted || '', dto.workCategory || 'none', dto.costCategory || 'none', dto.comment || '');
3440
+ return new EstimateItemModel(dto.id || v4(), dto.description || '', dto.type || '', dto.quantity || 0, dto.quantityAdjusted || 0, dto.units || 0, dto.unitsAdjusted || 0, dto.price || '', dto.priceAdjusted || '', dto.workCategory || 'none', dto.costCategory || 'none', dto.comment || '', dto.vatExcluded || false);
3433
3441
  }
3434
3442
  static equal(a, b) {
3435
3443
  return (a?.id === b?.id &&
@@ -3459,6 +3467,12 @@ const b$1 = (value = '0') => {
3459
3467
  return new Big('0');
3460
3468
  }
3461
3469
  };
3470
+ function isLabourWorkCategory(value) {
3471
+ return ['check', 'rr', 'repair', 'removed'].includes(value);
3472
+ }
3473
+ function isPaintWorkCategory(value) {
3474
+ return ['blend', 'paint'].includes(value);
3475
+ }
3462
3476
  class EstimateModel {
3463
3477
  id = v4();
3464
3478
  source = 'manual';
@@ -3556,18 +3570,13 @@ class EstimateModel {
3556
3570
  calculate() {
3557
3571
  this.summaryNet = this.getSummaryNet(false);
3558
3572
  if (this.adjusted) {
3559
- this.summaryAdjusted = this.getSummary(this.summaryNet, this.sundryRate, this.sundryMax, this.sundryFixed, this.sundryMethod, this.partsDiscount, this.paintDiscount, this.adjusted);
3573
+ const summaryNetAdjusted = this.getSummaryNet(true);
3574
+ this.summaryAdjusted = this.getSummary(summaryNetAdjusted, this.sundryRate, this.sundryMax, this.sundryFixed, this.sundryMethod, this.partsDiscount, this.paintDiscount, true);
3560
3575
  }
3561
- this.summary = this.getSummary(this.summaryNet, this.sundryRate, this.sundryMax, this.sundryFixed, this.sundryMethod, this.partsDiscount, this.paintDiscount, this.adjusted);
3562
- this.net = b$1(0)
3563
- .add(this.summary.labour)
3564
- .add(this.summary.none)
3565
- .add(this.summary.parts)
3566
- .add(this.summary.pm)
3567
- .add(this.summary.specialist)
3568
- .toFixed(2);
3569
- this.vat = b$1(this.net || '0').mul(this.vatRate || '0').toFixed(2);
3570
- this.gross = b$1(this.net || '0').add(this.vat || '0').toFixed(2);
3576
+ this.summary = this.getSummary(this.summaryNet, this.sundryRate, this.sundryMax, this.sundryFixed, this.sundryMethod, this.partsDiscount, this.paintDiscount, false);
3577
+ this.net = this.summary.net;
3578
+ this.vat = this.summary.vat;
3579
+ this.gross = this.summary.gross;
3571
3580
  }
3572
3581
  /**
3573
3582
  * Returns the net summary (before sundries and discounts) of the estimate.
@@ -3579,7 +3588,7 @@ class EstimateModel {
3579
3588
  getSummaryNet(adjusted = false) {
3580
3589
  const summary = this.items.reduce((map, item) => {
3581
3590
  map[item.costCategory] = b$1(map[item.costCategory] || '0')
3582
- .add(item.getLineValue(this.labourRate, this.timeBasisSafe, adjusted))
3591
+ .add(item.getLineValue(this.labourRate, this.timeBasisSafe, adjusted, this.source === 'gtmotive' ? false : undefined))
3583
3592
  .toFixed(2);
3584
3593
  return map;
3585
3594
  }, {
@@ -3598,13 +3607,19 @@ class EstimateModel {
3598
3607
  });
3599
3608
  if (this.source === 'audatex') {
3600
3609
  const mechHours = this.items
3601
- .filter(item => item.workCategory !== 'paint')
3602
- .reduce((h, item) => h.add(b$1(item.getTotalUnits(adjusted))), b$1())
3610
+ .reduce((h, item) => {
3611
+ return isLabourWorkCategory(item.workCategory) ?
3612
+ h.add(b$1(item.getTotalUnits(adjusted))) :
3613
+ h;
3614
+ }, b$1())
3603
3615
  .div(this.timeBasisSafe || '1')
3604
3616
  .round(2);
3605
3617
  const paintHours = this.items
3606
- .filter(item => item.workCategory === 'paint')
3607
- .reduce((h, item) => h.add(b$1(item.getTotalUnits(adjusted))), b$1())
3618
+ .reduce((h, item) => {
3619
+ return isPaintWorkCategory(item.workCategory) ?
3620
+ h.add(b$1(item.getTotalUnits(adjusted))) :
3621
+ h;
3622
+ }, b$1())
3608
3623
  .div(this.timeBasisSafe || '1')
3609
3624
  .round(1);
3610
3625
  const mechCost = mechHours.mul(this.labourRate || '0');
@@ -3615,7 +3630,6 @@ class EstimateModel {
3615
3630
  }
3616
3631
  /**
3617
3632
  * Applies the sundry and discount values to the net summary.
3618
-
3619
3633
  */
3620
3634
  getSummary(summaryNet, sundryRate, sundryMax, sundryFixed, sundryMethod, partsDiscount, paintDiscount, adjusted) {
3621
3635
  const partsDisc = b$1('1').minus(partsDiscount || '0');
@@ -3637,12 +3651,19 @@ class EstimateModel {
3637
3651
  .add(summaryNet.none)
3638
3652
  .add(parts)
3639
3653
  .add(summaryNet.pm)
3654
+ .add(summaryNet.pl)
3640
3655
  .add(summaryNet.specialist)
3656
+ .add(summaryNet.other)
3641
3657
  .toFixed(2);
3642
3658
  const vat = b$1(net || '0')
3643
3659
  .mul(this.vatRate || '0')
3644
3660
  .toFixed(2);
3645
- const gross = b$1(net || '0').add(vat || '0').toFixed(2);
3661
+ let gross = b$1(net || '0').add(vat || '0').toFixed(2);
3662
+ // calculate the total value of lines that are VAT excluded
3663
+ const vatExcludeTotal = this.items.reduce((p, c) => c.vatExcluded ?
3664
+ p.add(c.getLineValue(this.labourRate, this.timeBasisSafe, adjusted, true)) :
3665
+ p, b$1());
3666
+ gross = b$1(gross).add(vatExcludeTotal).toFixed(2);
3646
3667
  return {
3647
3668
  labour: summaryNet.labour,
3648
3669
  none: summaryNet.none,
@@ -3797,6 +3818,13 @@ const getEmptyGeoLocation = () => ({
3797
3818
  timestamp: ''
3798
3819
  });
3799
3820
 
3821
+ /**
3822
+ * Return true IFF the array contains only strings
3823
+ */
3824
+ const isArrayString = (value) => {
3825
+ return Array.isArray(value) && value.every(i => typeof i === 'string');
3826
+ };
3827
+
3800
3828
  /**
3801
3829
  * Return true if the argument is a plain object {}, i.e. not an array, null.
3802
3830
  */
@@ -3804,7 +3832,69 @@ function isPlainObject(value) {
3804
3832
  return typeof value === 'object' && value !== null && !Array.isArray(value);
3805
3833
  }
3806
3834
 
3835
+ /**
3836
+ * Return an object omitting properties specified by key(s)
3837
+ *
3838
+ * @param obj object to be processed
3839
+ * @param omitKey key or array of keys to be omitted
3840
+ */
3841
+ const omit = (obj, omitKey) => {
3842
+ return Object.keys(obj).reduce((result, key) => {
3843
+ if (Array.isArray(omitKey)) {
3844
+ if (!omitKey.includes(key)) {
3845
+ result[key] = obj[key];
3846
+ }
3847
+ }
3848
+ else {
3849
+ if (omitKey !== key) {
3850
+ result[key] = obj[key];
3851
+ }
3852
+ }
3853
+ return result;
3854
+ }, {});
3855
+ };
3856
+
3857
+ /**
3858
+ * Try to parse the value as JSON if it looks like a JSON encoded string, return
3859
+ * the original value if it's not a JSON string or parsing fails.
3860
+ */
3861
+ const tryJson = (value) => {
3862
+ if (typeof value === 'string' && ['{', '['].includes(value.substring(0, 1))) {
3863
+ try {
3864
+ return JSON.parse(value);
3865
+ }
3866
+ catch (e) {
3867
+ return value;
3868
+ }
3869
+ }
3870
+ return value;
3871
+ };
3872
+
3873
+ const nullables = new Set([
3874
+ 'created',
3875
+ 'modified',
3876
+ 'reference',
3877
+ 'jobDate',
3878
+ 'followUpDate',
3879
+ 'followUpStatus',
3880
+ 'followUpNote',
3881
+ ]);
3807
3882
  let jobStaticProps;
3883
+ function getStaticProps() {
3884
+ if (jobStaticProps) {
3885
+ return jobStaticProps;
3886
+ }
3887
+ return jobStaticProps = new Set([
3888
+ ...Object.getOwnPropertyNames(VasJobDocumentModel.empty()),
3889
+ 'assignee'
3890
+ ]);
3891
+ }
3892
+ function isArrayOfFields(value) {
3893
+ return !!value && Array.isArray(value);
3894
+ }
3895
+ function isDictionaryOfFields(value) {
3896
+ return !!value && isPlainObject(value);
3897
+ }
3808
3898
  /**
3809
3899
  * VasJobBaseModel
3810
3900
  */
@@ -3831,6 +3921,9 @@ class VasJobBaseModel extends VasRestrictedAccountObjectModel {
3831
3921
  pendingFields;
3832
3922
  childModified;
3833
3923
  version;
3924
+ followUpDate;
3925
+ followUpStatus;
3926
+ followUpNote;
3834
3927
  geoLocation;
3835
3928
  files;
3836
3929
  fields;
@@ -3839,7 +3932,7 @@ class VasJobBaseModel extends VasRestrictedAccountObjectModel {
3839
3932
  reports;
3840
3933
  tasks;
3841
3934
  instruction;
3842
- constructor(id, created, serverCreated, createdBy, modified, serverModified, modifiedBy, createdByName, modifiedByName, account, accessGroup, reference, jobDate, jobStatus, jobStatusLastUpdate, jobType, assigneeId, formId, timeZoneOffset, pendingFields, childModified, version, geoLocation, files, fields, jobEmails, notes, reports, tasks, instruction) {
3935
+ constructor(id, created, serverCreated, createdBy, modified, serverModified, modifiedBy, createdByName, modifiedByName, account, accessGroup, reference, jobDate, jobStatus, jobStatusLastUpdate, jobType, assigneeId, formId, timeZoneOffset, pendingFields, childModified, version, followUpDate, followUpStatus, followUpNote, geoLocation, files, fields, jobEmails, notes, reports, tasks, instruction) {
3843
3936
  super(id, created, serverCreated, createdBy, modified, serverModified, modifiedBy, createdByName, modifiedByName, account, accessGroup);
3844
3937
  this.id = id;
3845
3938
  this.created = created;
@@ -3863,6 +3956,9 @@ class VasJobBaseModel extends VasRestrictedAccountObjectModel {
3863
3956
  this.pendingFields = pendingFields;
3864
3957
  this.childModified = childModified;
3865
3958
  this.version = version;
3959
+ this.followUpDate = followUpDate;
3960
+ this.followUpStatus = followUpStatus;
3961
+ this.followUpNote = followUpNote;
3866
3962
  this.geoLocation = geoLocation;
3867
3963
  this.files = files;
3868
3964
  this.fields = fields;
@@ -3882,11 +3978,7 @@ class VasJobBaseModel extends VasRestrictedAccountObjectModel {
3882
3978
  * Return the list of Job properties
3883
3979
  */
3884
3980
  get staticProperties() {
3885
- if (jobStaticProps) {
3886
- return jobStaticProps;
3887
- }
3888
- return jobStaticProps =
3889
- new Set(Object.getOwnPropertyNames(VasJobDocumentModel.empty()));
3981
+ return getStaticProps();
3890
3982
  }
3891
3983
  /**
3892
3984
  * Returns an object describing how many attachments were added to this job
@@ -3959,7 +4051,6 @@ class VasJobBaseModel extends VasRestrictedAccountObjectModel {
3959
4051
  if (!value || typeof value !== 'string') {
3960
4052
  return '';
3961
4053
  }
3962
- const fields = this.fields;
3963
4054
  return value.replace(/({[^}]*})/g, (match, token) => {
3964
4055
  const syntax = token.substring(1, token.length - 1);
3965
4056
  let [key, filter] = syntax.split('|');
@@ -4044,8 +4135,11 @@ class VasJobBaseModel extends VasRestrictedAccountObjectModel {
4044
4135
  'assigneeId',
4045
4136
  'timeZoneOffset',
4046
4137
  'pendingFields',
4047
- 'formId'
4048
- ]);
4138
+ 'formId',
4139
+ 'followUpDate',
4140
+ 'followUpStatus',
4141
+ 'followUpNote',
4142
+ ], (value, key) => value[key] === null && nullables.has(key) ? '~' : value[key]);
4049
4143
  }
4050
4144
  }
4051
4145
  class VasJobRelationalModel extends VasJobBaseModel {
@@ -4083,10 +4177,43 @@ class VasJobRelationalModel extends VasJobBaseModel {
4083
4177
  if (dto.fields !== undefined && !Array.isArray(dto.fields)) {
4084
4178
  throw Error('fields must be an array');
4085
4179
  }
4086
- return new VasJobRelationalModel(dto.id || '', dto.created || '', dto.serverCreated || '', dto.createdBy || '', dto.modified || '', dto.serverModified || '', dto.modifiedBy || '', dto.createdByName || '', dto.modifiedByName || '', dto.account || '', dto.accessGroup || '', dto.reference || '', dto.jobDate || '', dto.jobStatus || '', dto.jobStatusLastUpdate || '', dto.jobType || '', dto.assigneeId || '', dto.formId || dto.lastForm || '', dto.timeZoneOffset || moment().utcOffset(), dto.pendingFields || 0, dto.childModified || '', dto.version || 0, dto.geoLocation || getEmptyGeoLocation(), dto.files || [], (dto.fields || []).map(f => VasFieldModel.fromDto(f)), dto.jobEmails || [], dto.notes || [], dto.reports || [], dto.tasks || [], dto.instruction || null);
4180
+ return new VasJobRelationalModel(dto.id || '', dto.created || '', dto.serverCreated || '', dto.createdBy || '', dto.modified || '', dto.serverModified || '', dto.modifiedBy || '', dto.createdByName || '', dto.modifiedByName || '', dto.account || '', dto.accessGroup || '', dto.reference || '', dto.jobDate || '', dto.jobStatus || '', dto.jobStatusLastUpdate || '', dto.jobType || '', dto.assigneeId || '', dto.formId || dto.lastForm || '', dto.timeZoneOffset || moment().utcOffset(), dto.pendingFields || 0, dto.childModified || '', dto.version || 0, dto.followUpDate || '', dto.followUpStatus || '', dto.followUpNote || '', dto.geoLocation || getEmptyGeoLocation(), dto.files || [], (dto.fields || []).map(f => VasFieldModel.fromDto(f)), dto.jobEmails || [], dto.notes || [], dto.reports || [], dto.tasks || [], dto.instruction || null);
4087
4181
  }
4088
4182
  static empty() {
4089
- return new VasJobRelationalModel('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', moment().utcOffset(), 0, '', 0, getEmptyGeoLocation(), [], [], [], [], [], [], null);
4183
+ return new VasJobRelationalModel('', // id
4184
+ '', // created
4185
+ '', // serverCreated
4186
+ '', // createdBy
4187
+ '', // modified
4188
+ '', // serverModified
4189
+ '', // modifiedBy
4190
+ '', // createdByName
4191
+ '', // modifiedByName
4192
+ '', // account
4193
+ '', // accessGroup
4194
+ '', // reference
4195
+ '', // jobDate
4196
+ '', // jobStatus
4197
+ '', // jobStatusLastUpdate
4198
+ '', // jobType
4199
+ '', // assigneeId
4200
+ '', // formId
4201
+ moment().utcOffset(), // timeZoneOffset
4202
+ 0, // pendingFields: number,
4203
+ '', // childModified: string,
4204
+ 0, // version: number,
4205
+ '', // followUpDate: string,
4206
+ '', // followUpStatus: string,
4207
+ '', // followUpNote: string,
4208
+ getEmptyGeoLocation(), // geoLocation: GeoLocation,
4209
+ [], // files: Array<VasFileDto>,
4210
+ [], // fields: FType,
4211
+ [], // jobEmails: Array<VasJobEmailDto>,
4212
+ [], // notes: Array<VasNoteDto>,
4213
+ [], // reports: Array<VasReportDto>,
4214
+ [], // tasks: Array<VasTaskDto>,
4215
+ null // instruction: VasInstructionDto | null
4216
+ );
4090
4217
  }
4091
4218
  toDto() {
4092
4219
  return {
@@ -4112,6 +4239,9 @@ class VasJobRelationalModel extends VasJobBaseModel {
4112
4239
  pendingFields: this.pendingFields,
4113
4240
  childModified: this.childModified,
4114
4241
  version: this.version,
4242
+ followUpDate: this.followUpDate,
4243
+ followUpStatus: this.followUpStatus,
4244
+ followUpNote: this.followUpNote,
4115
4245
  geoLocation: this.geoLocation,
4116
4246
  files: this.files,
4117
4247
  fields: this.fields.map(f => f.toDto()),
@@ -4125,19 +4255,85 @@ class VasJobRelationalModel extends VasJobBaseModel {
4125
4255
  }
4126
4256
  class VasJobDocumentModel extends VasJobBaseModel {
4127
4257
  static fromRelationalDto(dto) {
4128
- return new VasJobDocumentModel(dto.id || '', dto.created || '', dto.serverCreated || '', dto.createdBy || '', dto.modified || '', dto.serverModified || '', dto.modifiedBy || '', dto.createdByName || '', dto.modifiedByName || '', dto.account || '', dto.accessGroup || '', dto.reference || '', dto.jobDate || '', dto.jobStatus || '', dto.jobStatusLastUpdate || '', dto.jobType || '', dto.assigneeId || '', dto.formId || dto.lastForm || '', dto.timeZoneOffset || moment().utcOffset(), dto.pendingFields || 0, dto.childModified || '', dto.version || 0, dto.geoLocation || getEmptyGeoLocation(), dto.files || [], (dto.fields || []).reduce((p, c) => {
4258
+ return new VasJobDocumentModel(dto.id || '', dto.created || '', dto.serverCreated || '', dto.createdBy || '', dto.modified || '', dto.serverModified || '', dto.modifiedBy || '', dto.createdByName || '', dto.modifiedByName || '', dto.account || '', dto.accessGroup || '', dto.reference || '', dto.jobDate || '', dto.jobStatus || '', dto.jobStatusLastUpdate || '', dto.jobType || '', dto.assigneeId || '', dto.formId || dto.lastForm || '', dto.timeZoneOffset || moment().utcOffset(), dto.pendingFields || 0, dto.childModified || '', dto.version || 0, dto.followUpDate || '', dto.followUpStatus || '', dto.followUpNote || '', dto.geoLocation || getEmptyGeoLocation(), dto.files || [], (dto.fields || []).reduce((p, c) => {
4129
4259
  p[c.controlName.replace('fields.', '')] = c.value;
4130
4260
  return p;
4131
4261
  }, {}), dto.jobEmails || [], dto.notes || [], dto.reports || [], dto.tasks || [], dto.instruction || null);
4132
4262
  }
4133
- static fromDto(dto) {
4134
- if (dto.fields !== undefined && !isPlainObject(dto.fields)) {
4135
- throw Error('fields must be an object');
4263
+ static fromDto(dto, options = { disableMigrateCheck: false }) {
4264
+ let fields = {};
4265
+ if (dto.fields !== undefined) {
4266
+ if (isArrayOfFields(dto.fields)) {
4267
+ for (const field of dto.fields) {
4268
+ fields[field.controlName.replace('fields.', '')] =
4269
+ tryJson(field.value);
4270
+ }
4271
+ }
4272
+ else if (isDictionaryOfFields(dto.fields)) {
4273
+ fields = dto.fields;
4274
+ }
4136
4275
  }
4137
- return new VasJobDocumentModel(dto.id || '', dto.created || '', dto.serverCreated || '', dto.createdBy || '', dto.modified || '', dto.serverModified || '', dto.modifiedBy || '', dto.createdByName || '', dto.modifiedByName || '', dto.account || '', dto.accessGroup || '', dto.reference || '', dto.jobDate || '', dto.jobStatus || '', dto.jobStatusLastUpdate || '', dto.jobType || '', dto.assigneeId || '', dto.formId || dto.lastForm || '', dto.timeZoneOffset || moment().utcOffset(), dto.pendingFields || 0, dto.childModified || '', dto.version || 0, dto.geoLocation || getEmptyGeoLocation(), dto.files || [], dto.fields || {}, dto.jobEmails || [], dto.notes || [], dto.reports || [], dto.tasks || [], dto.instruction || null);
4276
+ // this code is checking if a have a document in the old dynamic job style,
4277
+ // i.e. where there are keys in the job object that come from the form-group
4278
+ // names. I did consider comparing the number of keys in the dto vs the
4279
+ // number of expected keys, but this will fail if we try to read old objects
4280
+ // that don't have new properties added. So we always check by default. We
4281
+ // can skip this check by setting disableMigrateCheck in the options.
4282
+ if (!options || !options.disableMigrateCheck) {
4283
+ const ddto = dto;
4284
+ const actualKeys = Object.keys(ddto);
4285
+ actualKeys.reduce((f, groupName) => {
4286
+ if (getStaticProps().has(groupName)) {
4287
+ return f;
4288
+ }
4289
+ Object
4290
+ .keys(ddto[groupName])
4291
+ .forEach(controlName => {
4292
+ if (!controlName.startsWith('fields.')) {
4293
+ return;
4294
+ }
4295
+ f[controlName.slice(7)] = ddto[groupName][controlName];
4296
+ });
4297
+ return f;
4298
+ }, fields);
4299
+ }
4300
+ return new VasJobDocumentModel(dto.id || '', dto.created || '', dto.serverCreated || '', dto.createdBy || '', dto.modified || '', dto.serverModified || '', dto.modifiedBy || '', dto.createdByName || '', dto.modifiedByName || '', dto.account || '', dto.accessGroup || '', dto.reference || '', dto.jobDate || '', dto.jobStatus || '', dto.jobStatusLastUpdate || '', dto.jobType || '', dto.assigneeId || '', dto.formId || dto.lastForm || '', dto.timeZoneOffset || moment().utcOffset(), dto.pendingFields || 0, dto.childModified || '', dto.version || 0, dto.followUpDate || '', dto.followUpStatus || '', dto.followUpNote || '', dto.geoLocation || getEmptyGeoLocation(), dto.files || [], fields, dto.jobEmails || [], dto.notes || [], dto.reports || [], dto.tasks || [], dto.instruction || null);
4138
4301
  }
4139
4302
  static empty() {
4140
- return new VasJobDocumentModel('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', moment().utcOffset(), 0, '', 0, getEmptyGeoLocation(), [], {}, [], [], [], [], null);
4303
+ return new VasJobDocumentModel('', // id
4304
+ '', // created
4305
+ '', // serverCreated
4306
+ '', // createdBy
4307
+ '', // modified
4308
+ '', // serverModified
4309
+ '', // modifiedBy
4310
+ '', // createdByName
4311
+ '', // modifiedByName
4312
+ '', // account
4313
+ '', // accessGroup
4314
+ '', // reference
4315
+ '', // jobDate
4316
+ '', // jobStatus
4317
+ '', // jobStatusLastUpdate
4318
+ '', // jobType
4319
+ '', // assigneeId
4320
+ '', // formId
4321
+ moment().utcOffset(), // timeZoneOffset
4322
+ 0, // pendingFields: number,
4323
+ '', // childModified: string,
4324
+ 0, // version: number,
4325
+ '', // followUpDate: string,
4326
+ '', // followUpStatus: string,
4327
+ '', // followUpNote: string,
4328
+ getEmptyGeoLocation(), // geoLocation: GeoLocation,
4329
+ [], // files: Array<VasFileDto>,
4330
+ {}, // fields: FType,
4331
+ [], // jobEmails: Array<VasJobEmailDto>,
4332
+ [], // notes: Array<VasNoteDto>,
4333
+ [], // reports: Array<VasReportDto>,
4334
+ [], // tasks: Array<VasTaskDto>,
4335
+ null // instruction: VasInstructionDto | null
4336
+ );
4141
4337
  }
4142
4338
  toDto() {
4143
4339
  return {
@@ -4163,6 +4359,9 @@ class VasJobDocumentModel extends VasJobBaseModel {
4163
4359
  pendingFields: this.pendingFields,
4164
4360
  childModified: this.childModified,
4165
4361
  version: this.version,
4362
+ followUpDate: this.followUpDate,
4363
+ followUpStatus: this.followUpStatus,
4364
+ followUpNote: this.followUpNote,
4166
4365
  geoLocation: this.geoLocation,
4167
4366
  files: this.files,
4168
4367
  fields: this.fields,
@@ -4778,51 +4977,6 @@ class VasVehicleModel extends VasAccountObjectModel {
4778
4977
  }
4779
4978
  }
4780
4979
 
4781
- /**
4782
- * Return true IFF the array contains only strings
4783
- */
4784
- const isArrayString = (value) => {
4785
- return Array.isArray(value) && value.every(i => typeof i === 'string');
4786
- };
4787
-
4788
- /**
4789
- * Return an object omitting properties specified by key(s)
4790
- *
4791
- * @param obj object to be processed
4792
- * @param omitKey key or array of keys to be omitted
4793
- */
4794
- const omit = (obj, omitKey) => {
4795
- return Object.keys(obj).reduce((result, key) => {
4796
- if (Array.isArray(omitKey)) {
4797
- if (!omitKey.includes(key)) {
4798
- result[key] = obj[key];
4799
- }
4800
- }
4801
- else {
4802
- if (omitKey !== key) {
4803
- result[key] = obj[key];
4804
- }
4805
- }
4806
- return result;
4807
- }, {});
4808
- };
4809
-
4810
- /**
4811
- * Try to parse the value as JSON if it looks like a JSON encoded string, return
4812
- * the original value if it's not a JSON string or parsing fails.
4813
- */
4814
- const tryJson = (value) => {
4815
- if (typeof value === 'string' && ['{', '['].includes(value.substring(0, 1))) {
4816
- try {
4817
- return JSON.parse(value);
4818
- }
4819
- catch (e) {
4820
- return value;
4821
- }
4822
- }
4823
- return value;
4824
- };
4825
-
4826
4980
  /**
4827
4981
  * Generated bundle index. Do not edit.
4828
4982
  */