@finsys/core 2.2.0 → 2.3.1

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.
package/dist/index.d.cts CHANGED
@@ -428,6 +428,8 @@ declare function getDisplayName(fieldName: string): string;
428
428
  declare function extractTimePeriods(columnNames: string[]): string[];
429
429
  declare function groupColumnsByTimePeriod(columnNames: string[]): Record<string, Record<string, string>>;
430
430
  declare function groupFieldsByPattern(fields: FieldData[]): Record<string, FieldData[]>;
431
+ /** Returns human-friendly display names for field groups. */
432
+ declare function getGroupDisplayNames(): Record<string, string>;
431
433
  declare function buildFileFieldTables(ihsData: Record<string, unknown>): Record<string, FileFieldTableData>;
432
434
  declare function processIhsDetails(ihsData: Record<string, unknown>): IhsFieldDetail[];
433
435
  declare function groupDetailsByCategory(details: IhsFieldDetail[]): IhsDetailCategory[];
@@ -467,4 +469,51 @@ declare enum ExtractionFileType {
467
469
  Ic = "ic"
468
470
  }
469
471
 
470
- export { BASE_FIELD_SPECS, BasicFormField, type Category, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DropdownOption, type EditorValidator, ExtractionFileType, ExtractionJobStatus, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, FormSpec, type FormValidatorDefinitions, type IhsDetailCategory, type IhsFieldDetail, IhsValueFormat, type PageConfig, type RHFSchemaOutput, type RHFStep, type ResolvedField, Role, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type UnifiedFormConfig, type Validator, applyDynamicTitles, buildFileFieldTables, evaluateExpression, extractTimePeriods, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getPastMonthLabel, getPastYearLabel, getStepDefaultValues, getStepSchema, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, processIhsDetails, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
472
+ declare enum DocExtractionStatus {
473
+ NotUploaded = "not_uploaded",
474
+ Uploaded = "uploaded",
475
+ Queued = "queued",
476
+ Processing = "processing",
477
+ Extracted = "extracted",
478
+ Failed = "failed",
479
+ Unknown = "unknown"
480
+ }
481
+ interface ExtractionJobRecord {
482
+ fileType: string;
483
+ status: string;
484
+ errorMessage?: string | null;
485
+ }
486
+ interface DocExtractionResult {
487
+ fileType: ExtractionFileType;
488
+ status: DocExtractionStatus;
489
+ displayName: string;
490
+ populatedColumns: string[];
491
+ totalColumns: number;
492
+ errorMessage?: string | null;
493
+ }
494
+ interface ExtractionStatusResult {
495
+ documents: DocExtractionResult[];
496
+ summary: {
497
+ total: number;
498
+ extracted: number;
499
+ failed: number;
500
+ pending: number;
501
+ notUploaded: number;
502
+ };
503
+ }
504
+ /**
505
+ * Determines per-document extraction status from IHS record data.
506
+ *
507
+ * For multi-file document types (bank statements, financial statements, EPF,
508
+ * payslips) the result contains one entry per uploaded file, indexed in the
509
+ * same order as the files appear in the IHS record's aggregate array.
510
+ * For single-file types (SSM, Form 9, IC) there is one entry.
511
+ *
512
+ * @param ihsRecord - The IHS application record (any shape satisfying Record<string, unknown>)
513
+ * @param jobRecords - Extraction job records for this IHS. Pass the array (even if empty)
514
+ * when job records were fetched. Omit or pass undefined when job records are unavailable;
515
+ * this produces `Unknown` status for uploaded-but-unextracted documents rather than `Uploaded`.
516
+ */
517
+ declare function resolveExtractionStatus(ihsRecord: Record<string, unknown>, jobRecords?: ExtractionJobRecord[]): ExtractionStatusResult;
518
+
519
+ export { BASE_FIELD_SPECS, BasicFormField, type Category, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DocExtractionResult, DocExtractionStatus, type DropdownOption, type EditorValidator, ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, FormSpec, type FormValidatorDefinitions, type IhsDetailCategory, type IhsFieldDetail, IhsValueFormat, type PageConfig, type RHFSchemaOutput, type RHFStep, type ResolvedField, Role, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type UnifiedFormConfig, type Validator, applyDynamicTitles, buildFileFieldTables, evaluateExpression, extractTimePeriods, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getStepDefaultValues, getStepSchema, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
package/dist/index.d.ts CHANGED
@@ -428,6 +428,8 @@ declare function getDisplayName(fieldName: string): string;
428
428
  declare function extractTimePeriods(columnNames: string[]): string[];
429
429
  declare function groupColumnsByTimePeriod(columnNames: string[]): Record<string, Record<string, string>>;
430
430
  declare function groupFieldsByPattern(fields: FieldData[]): Record<string, FieldData[]>;
431
+ /** Returns human-friendly display names for field groups. */
432
+ declare function getGroupDisplayNames(): Record<string, string>;
431
433
  declare function buildFileFieldTables(ihsData: Record<string, unknown>): Record<string, FileFieldTableData>;
432
434
  declare function processIhsDetails(ihsData: Record<string, unknown>): IhsFieldDetail[];
433
435
  declare function groupDetailsByCategory(details: IhsFieldDetail[]): IhsDetailCategory[];
@@ -467,4 +469,51 @@ declare enum ExtractionFileType {
467
469
  Ic = "ic"
468
470
  }
469
471
 
470
- export { BASE_FIELD_SPECS, BasicFormField, type Category, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DropdownOption, type EditorValidator, ExtractionFileType, ExtractionJobStatus, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, FormSpec, type FormValidatorDefinitions, type IhsDetailCategory, type IhsFieldDetail, IhsValueFormat, type PageConfig, type RHFSchemaOutput, type RHFStep, type ResolvedField, Role, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type UnifiedFormConfig, type Validator, applyDynamicTitles, buildFileFieldTables, evaluateExpression, extractTimePeriods, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getPastMonthLabel, getPastYearLabel, getStepDefaultValues, getStepSchema, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, processIhsDetails, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
472
+ declare enum DocExtractionStatus {
473
+ NotUploaded = "not_uploaded",
474
+ Uploaded = "uploaded",
475
+ Queued = "queued",
476
+ Processing = "processing",
477
+ Extracted = "extracted",
478
+ Failed = "failed",
479
+ Unknown = "unknown"
480
+ }
481
+ interface ExtractionJobRecord {
482
+ fileType: string;
483
+ status: string;
484
+ errorMessage?: string | null;
485
+ }
486
+ interface DocExtractionResult {
487
+ fileType: ExtractionFileType;
488
+ status: DocExtractionStatus;
489
+ displayName: string;
490
+ populatedColumns: string[];
491
+ totalColumns: number;
492
+ errorMessage?: string | null;
493
+ }
494
+ interface ExtractionStatusResult {
495
+ documents: DocExtractionResult[];
496
+ summary: {
497
+ total: number;
498
+ extracted: number;
499
+ failed: number;
500
+ pending: number;
501
+ notUploaded: number;
502
+ };
503
+ }
504
+ /**
505
+ * Determines per-document extraction status from IHS record data.
506
+ *
507
+ * For multi-file document types (bank statements, financial statements, EPF,
508
+ * payslips) the result contains one entry per uploaded file, indexed in the
509
+ * same order as the files appear in the IHS record's aggregate array.
510
+ * For single-file types (SSM, Form 9, IC) there is one entry.
511
+ *
512
+ * @param ihsRecord - The IHS application record (any shape satisfying Record<string, unknown>)
513
+ * @param jobRecords - Extraction job records for this IHS. Pass the array (even if empty)
514
+ * when job records were fetched. Omit or pass undefined when job records are unavailable;
515
+ * this produces `Unknown` status for uploaded-but-unextracted documents rather than `Uploaded`.
516
+ */
517
+ declare function resolveExtractionStatus(ihsRecord: Record<string, unknown>, jobRecords?: ExtractionJobRecord[]): ExtractionStatusResult;
518
+
519
+ export { BASE_FIELD_SPECS, BasicFormField, type Category, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DocExtractionResult, DocExtractionStatus, type DropdownOption, type EditorValidator, ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, FormSpec, type FormValidatorDefinitions, type IhsDetailCategory, type IhsFieldDetail, IhsValueFormat, type PageConfig, type RHFSchemaOutput, type RHFStep, type ResolvedField, Role, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type UnifiedFormConfig, type Validator, applyDynamicTitles, buildFileFieldTables, evaluateExpression, extractTimePeriods, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getStepDefaultValues, getStepSchema, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
package/dist/index.js CHANGED
@@ -9350,6 +9350,9 @@ var GROUP_DISPLAY_NAMES = {
9350
9350
  ssm_documents: "SSM Company Information",
9351
9351
  ic_documents: "Identification Card"
9352
9352
  };
9353
+ function getGroupDisplayNames() {
9354
+ return GROUP_DISPLAY_NAMES;
9355
+ }
9353
9356
  function isNumericField(fieldName) {
9354
9357
  const patterns = [
9355
9358
  "balance",
@@ -9492,9 +9495,12 @@ function processIhsDetails(ihsData) {
9492
9495
  const specs = getBaseFieldSpecs();
9493
9496
  const fileColumnSet = /* @__PURE__ */ new Set();
9494
9497
  for (const field of specs) {
9495
- if (field.type === "file" && field.ihs_column_names) {
9496
- for (const col of field.ihs_column_names) {
9497
- fileColumnSet.add(col);
9498
+ if (field.type === "file") {
9499
+ if (field.name) fileColumnSet.add(field.name);
9500
+ if (field.ihs_column_names) {
9501
+ for (const col of field.ihs_column_names) {
9502
+ fileColumnSet.add(col);
9503
+ }
9498
9504
  }
9499
9505
  }
9500
9506
  }
@@ -9566,10 +9572,162 @@ var ExtractionFileType = /* @__PURE__ */ ((ExtractionFileType2) => {
9566
9572
  ExtractionFileType2["Ic"] = "ic";
9567
9573
  return ExtractionFileType2;
9568
9574
  })(ExtractionFileType || {});
9575
+
9576
+ // src/extraction-status.ts
9577
+ var DocExtractionStatus = /* @__PURE__ */ ((DocExtractionStatus2) => {
9578
+ DocExtractionStatus2["NotUploaded"] = "not_uploaded";
9579
+ DocExtractionStatus2["Uploaded"] = "uploaded";
9580
+ DocExtractionStatus2["Queued"] = "queued";
9581
+ DocExtractionStatus2["Processing"] = "processing";
9582
+ DocExtractionStatus2["Extracted"] = "extracted";
9583
+ DocExtractionStatus2["Failed"] = "failed";
9584
+ DocExtractionStatus2["Unknown"] = "unknown";
9585
+ return DocExtractionStatus2;
9586
+ })(DocExtractionStatus || {});
9587
+ var FILE_TYPE_TO_GROUP = {
9588
+ ["bankStatements" /* BankStatement */]: "bank_statements",
9589
+ ["financialStatements" /* FinancialStatement */]: "financials",
9590
+ ["epfStatements" /* Epf */]: "epf_statements",
9591
+ ["payslips" /* Payslip */]: "payslip_statements",
9592
+ ["ssm" /* Ssm */]: "ssm_documents",
9593
+ ["form9" /* Form9 */]: "form9",
9594
+ ["ic" /* Ic */]: "ic_documents"
9595
+ };
9596
+ var _specs = getBaseFieldSpecs();
9597
+ var _fileFields = _specs.filter((f) => f.type === "file" && f.ihs_column_names?.length);
9598
+ var _grouped = groupFieldsByPattern(_fileFields);
9599
+ var _groupDisplayNames = getGroupDisplayNames();
9600
+ function isPopulated(value) {
9601
+ if (value === null || value === void 0 || value === "") return false;
9602
+ if (value === "Not Specified") return false;
9603
+ return true;
9604
+ }
9605
+ function countUploadedFiles(ihsRecord, aggregateKey) {
9606
+ const raw = ihsRecord[aggregateKey];
9607
+ if (!raw) return 0;
9608
+ if (typeof raw === "string") {
9609
+ try {
9610
+ const parsed = JSON.parse(raw);
9611
+ if (Array.isArray(parsed)) return parsed.length;
9612
+ } catch {
9613
+ return 1;
9614
+ }
9615
+ }
9616
+ if (Array.isArray(raw)) return raw.length;
9617
+ return 1;
9618
+ }
9619
+ function getPopulatedColumns(columns, ihsRecord) {
9620
+ return columns.filter((col) => isPopulated(ihsRecord[col]));
9621
+ }
9622
+ function resolveDocStatus(columns, ihsRecord, uploaded, jobRecord, hasJobRecords) {
9623
+ const populated = getPopulatedColumns(columns, ihsRecord);
9624
+ const hasExtractedData = populated.length > 0;
9625
+ let status;
9626
+ let errorMessage;
9627
+ if (!uploaded) {
9628
+ status = "not_uploaded" /* NotUploaded */;
9629
+ } else if (hasJobRecords) {
9630
+ if (jobRecord) {
9631
+ if (jobRecord.status === "queued" /* Queued */) {
9632
+ status = "queued" /* Queued */;
9633
+ } else if (jobRecord.status === "processing" /* Processing */) {
9634
+ status = "processing" /* Processing */;
9635
+ } else if (jobRecord.status === "failed" /* Failed */) {
9636
+ if (hasExtractedData) {
9637
+ status = "extracted" /* Extracted */;
9638
+ errorMessage = jobRecord.errorMessage;
9639
+ } else {
9640
+ status = "failed" /* Failed */;
9641
+ errorMessage = jobRecord.errorMessage;
9642
+ }
9643
+ } else if (jobRecord.status === "succeeded" /* Succeeded */ || hasExtractedData) {
9644
+ status = "extracted" /* Extracted */;
9645
+ } else {
9646
+ status = "uploaded" /* Uploaded */;
9647
+ }
9648
+ } else if (hasExtractedData) {
9649
+ status = "extracted" /* Extracted */;
9650
+ } else {
9651
+ status = "uploaded" /* Uploaded */;
9652
+ }
9653
+ } else if (hasExtractedData) {
9654
+ status = "extracted" /* Extracted */;
9655
+ } else {
9656
+ status = "unknown" /* Unknown */;
9657
+ }
9658
+ return { status, errorMessage };
9659
+ }
9660
+ function resolveExtractionStatus(ihsRecord, jobRecords) {
9661
+ const documents = [];
9662
+ const hasJobRecords = jobRecords !== void 0;
9663
+ for (const fileType of Object.values(ExtractionFileType)) {
9664
+ const groupName = FILE_TYPE_TO_GROUP[fileType];
9665
+ const fields = _grouped[groupName] ?? [];
9666
+ const displayName = _groupDisplayNames[groupName] ?? fileType;
9667
+ const uploadedCount = countUploadedFiles(ihsRecord, fileType);
9668
+ const isUploaded = uploadedCount > 0 || fields.some((f) => f.name && isPopulated(ihsRecord[f.name]));
9669
+ const matchingJobs = jobRecords?.filter((j) => j.fileType === fileType) ?? [];
9670
+ if (fields.length <= 1) {
9671
+ const field = fields[0];
9672
+ const columns = field?.ihs_column_names ?? [];
9673
+ const populated = getPopulatedColumns(columns, ihsRecord);
9674
+ const { status, errorMessage } = resolveDocStatus(
9675
+ columns,
9676
+ ihsRecord,
9677
+ isUploaded,
9678
+ matchingJobs[0],
9679
+ hasJobRecords
9680
+ );
9681
+ documents.push({
9682
+ fileType,
9683
+ status,
9684
+ displayName,
9685
+ populatedColumns: populated,
9686
+ totalColumns: columns.length,
9687
+ errorMessage
9688
+ });
9689
+ } else {
9690
+ const count = Math.max(uploadedCount, 1);
9691
+ for (let idx = 0; idx < count; idx++) {
9692
+ const field = fields[idx];
9693
+ const columns = field?.ihs_column_names ?? [];
9694
+ const populated = getPopulatedColumns(columns, ihsRecord);
9695
+ const fileUploaded = idx < uploadedCount;
9696
+ const { status, errorMessage } = resolveDocStatus(
9697
+ columns,
9698
+ ihsRecord,
9699
+ fileUploaded,
9700
+ matchingJobs[idx],
9701
+ hasJobRecords
9702
+ );
9703
+ documents.push({
9704
+ fileType,
9705
+ status,
9706
+ displayName,
9707
+ populatedColumns: populated,
9708
+ totalColumns: columns.length,
9709
+ errorMessage
9710
+ });
9711
+ }
9712
+ }
9713
+ }
9714
+ const summary = documents.reduce(
9715
+ (acc, d) => {
9716
+ if (d.status === "extracted" /* Extracted */) acc.extracted++;
9717
+ else if (d.status === "failed" /* Failed */) acc.failed++;
9718
+ else if (d.status === "not_uploaded" /* NotUploaded */) acc.notUploaded++;
9719
+ else acc.pending++;
9720
+ return acc;
9721
+ },
9722
+ { total: documents.length, extracted: 0, failed: 0, pending: 0, notUploaded: 0 }
9723
+ );
9724
+ return { documents, summary };
9725
+ }
9569
9726
  export {
9570
9727
  BASE_FIELD_SPECS,
9571
9728
  BasicFormField,
9572
9729
  DEFAULT_VALIDATOR_DEFINITIONS,
9730
+ DocExtractionStatus,
9573
9731
  ExtractionFileType,
9574
9732
  ExtractionJobStatus,
9575
9733
  FIELD_TYPE_DEFINITIONS,
@@ -9595,6 +9753,7 @@ export {
9595
9753
  getCategoryName,
9596
9754
  getDisplayName,
9597
9755
  getDisplayNames,
9756
+ getGroupDisplayNames,
9598
9757
  getPastMonthLabel,
9599
9758
  getPastYearLabel,
9600
9759
  getStepDefaultValues,
@@ -9604,6 +9763,7 @@ export {
9604
9763
  groupFieldsByCategory,
9605
9764
  groupFieldsByPattern,
9606
9765
  processIhsDetails,
9766
+ resolveExtractionStatus,
9607
9767
  resolvePageFields,
9608
9768
  validateFormConfig,
9609
9769
  validateFormSpec,