@fabriktor/fx 0.0.123 → 0.0.125

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.
@@ -1,5 +1,5 @@
1
1
  import type { BillableOperator, PayrollsOperator, QueryOptions } from "@fabriktor/client";
2
- import { ColPayrollsPayrolls, ColPayrollsHourBanks, ColPayrollsPayables, ColPayrollsAdjustments, ColPayrollsAdjustmentFolders, ColPayrollsPayConfigs, ColPayrollsEmployeePayConfigs, ColPayrollsAdjustmentRecords, ColPayrollsAdjustmentAggregates, ColPayrollsPayrollPrograms, type Payroll, type HourBank, type Payable, type Adjustment, type AdjustmentFolder, type PayConfig, type EmployeePayConfig, type AdjustmentRecord, type AdjustmentAggregate, type PayrollProgram, type InPayroll, type InAdjustment, type InAdjustmentFolder, type InPayConfig, type InEmployeePayConfig, type InPayrollProgram, type InAdjustmentAggregate, type PLPayrollsGeneratePayrollFromEntities, type InDate, type Period } from "@fabriktor/schema";
2
+ import { ColPayrollsPayrolls, ColPayrollsHourBanks, ColPayrollsPayables, ColPayrollsAdjustments, ColPayrollsAdjustmentFolders, ColPayrollsPayConfigs, ColPayrollsEmployeePayConfigs, ColPayrollsAdjustmentRecords, ColPayrollsAdjustmentAggregates, ColPayrollsPayrollPrograms, type Payroll, type HourBank, type Payable, type Adjustment, type AdjustmentFolder, type PayConfig, type EmployeePayConfig, type AdjustmentRecord, type AdjustmentAggregate, type PayrollProgram, type InPayroll, type InAdjustment, type InAdjustmentFolder, type InPayConfig, type InEmployeePayConfig, type InPayrollProgram, type InAdjustmentAggregate, type PLPayrollsGeneratePayrollFromEntities, type InDate, type Period, type Folder } from "@fabriktor/schema";
3
3
  import type { EmploymentActor, EmploymentReadContext } from "../contacts/scope.js";
4
4
  import { type SearchOptions, type SearchPage } from "../core/search.js";
5
5
  import type { MultiCreateAttempt } from "../core/multi-create.js";
@@ -87,12 +87,12 @@ export declare const payrollPolicies: {
87
87
  report: boolean;
88
88
  };
89
89
  adjustment_folders: {
90
+ archive: false;
91
+ remove: true;
90
92
  filters: "is_archived"[];
91
93
  employee_read: boolean;
92
94
  searchable: boolean;
93
95
  create: boolean;
94
- archive: boolean;
95
- remove: boolean;
96
96
  report: boolean;
97
97
  };
98
98
  pay_configs: {
@@ -204,6 +204,7 @@ export declare class PayrollsWorkspace {
204
204
  private adjustments;
205
205
  private config;
206
206
  private validateCommand;
207
+ updateFolder(actor: EmploymentActor, id: string, input: Folder): Promise<AdjustmentFolder>;
207
208
  setArchived(actor: EmploymentActor, resource: PayrollResource, record: PayrollRecord, value: boolean): Promise<void>;
208
209
  setEnabled(actor: EmploymentActor, record: PayrollProgram, is_enabled: boolean): Promise<void>;
209
210
  remove(actor: EmploymentActor, resource: PayrollResource, record: PayrollRecord): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import { isHTTPClientErr } from "@fabriktor/client";
2
2
  import { ColPayrollsPayrolls, ColPayrollsHourBanks, ColPayrollsPayables, ColPayrollsAdjustments, ColPayrollsAdjustmentFolders, ColPayrollsPayConfigs, ColPayrollsEmployeePayConfigs, ColPayrollsAdjustmentRecords, ColPayrollsAdjustmentAggregates, ColPayrollsPayrollPrograms, UserTypeEmployer, UserTypeEmployee, AdjustmentTypeRate, AdjustmentTypePerHour, AdjustmentTypePerPeriod, PayTypeFixed, PayTypePerHour, RecurrenceTypeDaily, RecurrenceTypeWeekly, RecurrenceTypeMonthly, RecurrenceTypeYearly, } from "@fabriktor/schema";
3
- import { employmentCanRead, employmentCatalogOwnerIDs, } from "../contacts/scope.js";
3
+ import { employmentCanRead, employmentCatalogOwnerIDs, employmentOwnsRecord, } from "../contacts/scope.js";
4
4
  import { normalizeIDs, requiredOperationID } from "../core/id.js";
5
5
  import { runOwnerScopeQuery } from "../core/query.js";
6
6
  import { runOwnerScopeSearch, emptySearchPage, } from "../core/search.js";
@@ -31,7 +31,7 @@ const catalog = {
31
31
  create: true,
32
32
  archive: true,
33
33
  };
34
- // The service README and record Rules() define this capability/filter table.
34
+ // Service routes, record behavior and Rules() define this capability/filter table.
35
35
  // A generic CRUD method in the client is not permission to edit an immutable record.
36
36
  export const payrollPolicies = {
37
37
  [PayrollResource.Payrolls]: {
@@ -82,7 +82,12 @@ export const payrollPolicies = {
82
82
  "is_archived",
83
83
  ],
84
84
  },
85
- [PayrollResource.Folders]: { ...catalog, filters: ["is_archived"] },
85
+ [PayrollResource.Folders]: {
86
+ ...catalog,
87
+ archive: false,
88
+ remove: true,
89
+ filters: ["is_archived"],
90
+ },
86
91
  [PayrollResource.PayConfigs]: {
87
92
  ...catalog,
88
93
  filters: ["type", "name", "currency", "is_archived"],
@@ -137,6 +142,9 @@ export const payrollRecurrenceTypes = [
137
142
  ];
138
143
  // record/config.go pctMoney uses basis.X100000. A displayed percentage is 100 times the fraction.
139
144
  export const payrollPercentageScale = 1000;
145
+ // Validation and access denials reject these transactional generation requests.
146
+ // A 409 can also come from idempotency middleware, so it cannot release a request.
147
+ const payrollGenerationRejectionStatuses = [400, 403];
140
148
  export class PayrollWorkflowError extends Error {
141
149
  reason;
142
150
  constructor(reason) {
@@ -152,7 +160,7 @@ function requirePayroll(value, reason) {
152
160
  export function payrollCanManage(actor, record) {
153
161
  return (employmentCanRead(actor) &&
154
162
  actor.active_mode === UserTypeEmployer &&
155
- (!record || record.owner_id === actor.owner_id));
163
+ (!record || employmentOwnsRecord(actor, record)));
156
164
  }
157
165
  export function payrollCanRead(actor, resource) {
158
166
  return (employmentCanRead(actor) &&
@@ -341,12 +349,13 @@ export class PayrollsWorkspace {
341
349
  return p.insertOnePayrollProgram({ in: command.input, ...request });
342
350
  }
343
351
  })().catch((error) => {
344
- // These three handlers roll back their transaction on validation failure.
345
- // Other responses remain uncertain and retain request/source checkpoints.
346
- const transactional = command.resource === PayrollResource.Payrolls ||
347
- command.resource === PayrollResource.HourBanks ||
348
- command.resource === PayrollResource.Payables;
349
- if (transactional && isHTTPClientErr(error) && error.status === 400) {
352
+ // Generation from configurations, hour banks and payables returns a payroll.
353
+ // A rejection on retry does not settle an earlier ambiguous submission.
354
+ if (!previous &&
355
+ resource === PayrollResource.Payrolls &&
356
+ isHTTPClientErr(error) &&
357
+ error.status !== undefined &&
358
+ payrollGenerationRejectionStatuses.includes(error.status)) {
350
359
  this.submitted.delete(attempt.idempotency_key);
351
360
  for (const key of sourceKeys)
352
361
  this.sourceRequests.delete(key);
@@ -479,6 +488,19 @@ export class PayrollsWorkspace {
479
488
  break;
480
489
  }
481
490
  }
491
+ async updateFolder(actor, id, input) {
492
+ await this.owned(actor, PayrollResource.Folders, id);
493
+ const folder_name = input.folder_name.trim();
494
+ requirePayroll(folder_name, "invalid");
495
+ await this.payrolls.replaceOneAdjustmentFolder({
496
+ id,
497
+ in: {
498
+ folder_name,
499
+ folder_description: input.folder_description.trim(),
500
+ },
501
+ });
502
+ return this.owned(actor, PayrollResource.Folders, id);
503
+ }
482
504
  async setArchived(actor, resource, record, value) {
483
505
  requirePayroll(payrollCanManage(actor, record) && payrollPolicies[resource].archive, "access");
484
506
  await this.owned(actor, resource, record.id);
@@ -487,9 +509,6 @@ export class PayrollsWorkspace {
487
509
  case PayrollResource.Adjustments:
488
510
  await this.payrolls.replaceOneAdjustment(opts);
489
511
  break;
490
- case PayrollResource.Folders:
491
- await this.payrolls.replaceOneAdjustmentFolder(opts);
492
- break;
493
512
  case PayrollResource.PayConfigs:
494
513
  await this.payrolls.replaceOnePayConfig(opts);
495
514
  break;
@@ -514,5 +533,7 @@ export class PayrollsWorkspace {
514
533
  await this.payrolls.deleteOnePayroll({ id: record.id });
515
534
  else if (resource === PayrollResource.Programs)
516
535
  await this.payrolls.deleteOnePayrollProgram({ id: record.id });
536
+ else if (resource === PayrollResource.Folders)
537
+ await this.payrolls.deleteOneAdjustmentFolder({ id: record.id });
517
538
  }
518
539
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabriktor/fx",
3
- "version": "0.0.123",
3
+ "version": "0.0.125",
4
4
  "description": "![Fabriktor Logo](./img/fabriktor-character.gif)",
5
5
  "type": "module",
6
6
  "exports": {