Wingold — legacy WinGold ERP export mapping (stub / orphaned)

The whole feature reduces to one idea: a flat sheet of GL/account mapping codes that tell zerp how to label data when exporting it into WinGold (a legacy jewellery/gold-trading accounting ERP). It is a code-mapping config, not a live two-way sync.

Status: minimal + currently orphaned. The admin UI exists and is wired into the context tree, but the GraphQL operations it calls (wingoldConfig, updateWingoldConfig, the Wingold type, WingoldCommonInput) do not exist in the current zerp-be schema.gql, and there is no wingold module, resolver, service, or schema in zerp-be/src/modules. There is also no pages/ route rendering the screen. Treat this as a stub / vestigial integration unless/until the backend half is (re)introduced. See §9.

Source: BE — none (no src/modules/wingold; only two stray references, see §8) · Admin zerp-admin/src/modules/wingold

1. Purpose & scope

WinGold is a long-standing Windows desktop accounting/inventory ERP widely used in the gold & jewellery trade (chart-of-accounts driven, with "Level 5" account codes, year/schedule codes, AR/AP group codes, receipt/payment mode codes, salesman codes, etc.). The field names in this module are exactly that vocabulary, so the module's role is:

  • Does (intent): store the set of WinGold reference codes that zerp must stamp onto records so its data can be exported into / reconciled against a WinGold installation — i.e. a one-time-per-tenant mapping table for an outbound legacy-ERP export.
  • Does NOT: perform any live sync, pull data from WinGold, schedule jobs, or call an external WinGold API. There is no transport layer in this codebase. The module is a config editor only, and even that is currently non-functional because the backend ops are missing.

What it explicitly is not in the current build: a working integration. It is config-shaped scaffolding.

2. Data model

There is no backend schema / collection for this in zerp-be. The only model is the admin-side TypeScript interface that mirrors the (missing) Wingold GraphQL type.

zerp-admin/src/modules/wingold/model.ts:

export interface IWingoldConfig {
  _id: string;
  level5Code: string;          // WinGold "Level 5" chart-of-accounts code
  yearCode: string;            // WinGold fiscal-year / period code
  scheduleCode: string;        // WinGold schedule (sub-ledger grouping) code
  controlAccountCode: string;  // control / parent GL account code
  arapGroupCode: string;       // AR/AP (receivables/payables) group code
  defaultRPModeCode: string;   // default Receipt/Payment mode code
  accountCode: string;         // default GL account code
  itemTypeCode: string;        // WinGold item/stock type code
  salesmanCode: string;        // WinGold salesman code
}
Field Type Required? Description (inferred from WinGold domain — names are the only spec)
_id string yes Document id of the single config record.
level5Code string no WinGold "Level 5" account-tree code (its deepest GL level).
yearCode string no Fiscal year / accounting period code in WinGold.
scheduleCode string no Schedule / sub-ledger grouping code.
controlAccountCode string no Control (parent) account code.
arapGroupCode string no Accounts-Receivable/Payable group code.
defaultRPModeCode string no Default Receipt/Payment mode code.
accountCode string no Default account code for postings.
itemTypeCode string no Item / stock type code.
salesmanCode string no Salesman code.
  • Enums: none. Every field is a free-text string code (entered via plain text inputs — see §7). There is no validation linking these to actual WinGold values.
  • Relationships / scoping / soft-delete: unknown — there is no backend schema to inspect. The admin treats it as a single per-tenant config document (singleton; fetched/updated by _id, no list/pagination).

3. API surface

GraphQL (referenced by admin, NOT present in schema.gql)

The admin defines these operations (zerp-admin/src/modules/wingold/gql/query.ts), but a grep of zerp-be/src/schema.gql returns none of them:

Operation Type Input Returns Permission
wingoldConfig Mutation and Query (same name, both defined) Wingold unknown (no BE def)
updateWingoldConfig Mutation wingold: WingoldCommonInput! Wingold unknown (no BE def)

Selection set (gql/fragment.ts):

fragment Wingold on Wingold {
  _id level5Code yearCode scheduleCode controlAccountCode
  arapGroupCode defaultRPModeCode accountCode itemTypeCode salesmanCode
}

Note the admin declares both a mutation wingoldConfig { ... } (intended "create") and a query wingoldConfig { ... } (read) — same operation name, two different operation types. Only the query is actually used by the screen (useLazyWingoldConfigPage); useCreateWingoldConfig is exported but never called. Because the backend type doesn't exist, all of these would fail at runtime against the current server.

REST

None.

4. Business rules & calculations

  • No calculations, no state machine, no side effects in this codebase. It is a flat key/value editor.
  • No validation — the Formik schema is empty (commented out, zerp-admin/src/modules/wingold/detail.tsx):
const FormSchema = Yup.object().shape({
  // installmentCycle: Yup.string().required(...)
  // ...all commented out...
});

and validationSchema={FormSchema} is itself commented out on the <Formik>. So every field is optional free text.

  • The intended export semantics (how these codes get stamped onto exported records, the WinGold file/format, the time format) are not implemented here. The only adjacent hint is an unused constant AP_WINGOLD_TIME_FORMAT = "YYYY-MM-DDThh:mm:ss" in zerp-be/src/constant.ts (no importers), suggesting a planned timestamp format for a WinGold export that was never built in this tree.

5. Permissions

Unknown / none enforced. The admin screen has no permission gate, and there is no backend resolver to carry @ApGqlAuthorize or a permission module/action. No CASL abilities reference Wingold.

6. Flows

6.1 Intended config-edit flow (currently broken — backend ops missing)

  1. User navigates to the Wingold Config screen → WingoldConfigPage (page.tsx) mounts and calls fetchWingold() on mount.
  2. fetchWingold() → context (context.tsx) runs useLazyWingoldConfigPage → fires the wingoldConfig query(would) return the Wingold document → stored in config state.
  3. Screen renders WingoldConfigDetail only when config?._id is truthy — so with no backend the form never renders (the guard {config?._id && <WingoldConfigDetail .../>} in page.tsx stays false).
  4. User edits the nine code fields and clicks Update ConfigupdateWingold(values)updateWingoldConfig(WingoldCommonInput!) mutation → on success toast "Settings Updated" and merge into config state.

Unhappy path (the current reality)

  • The wingoldConfig query resolves against a server that has no Wingold type / resolver, so it errors. toastSvc.graphQlError(err) surfaces the GraphQL error and config._id never gets set, so the form stays hidden. The page is effectively a no-op for an end user today.

7. Admin UI

  • Module: zerp-admin/src/modules/wingold/page.tsx, detail.tsx, context.tsx, model.ts, gql/{query,fragment}.ts.
  • Page route: none found. No file under zerp-admin/src/pages imports/renders WingoldConfigPage. The screen component exists but is not routed (orphaned). The context provider, however, is mounted globally via zerp-admin/src/Context.tsx (WingoldConfigContextProvider, lines 44 + 108).
  • Title: <ApPageTitle title="Wingold Config" />.
  • Form (detail.tsx): a single Formik form with nine ApTextInputs — Level 5 Code, Year Code, Schedule Code, Control Account Code, Arap Group Code, Default RPMode Code, Account Code, Item Type Code, Salesman Code — plus a fixed-footer Update Config ApButton (loading bound to updateLoading). ApSwitchInput / ApText are imported but unused. No validation (see §4).
  • Context methods (context.tsx): exposes config, fetchWingold(), updateWingold(values), loading, updateLoading via useWingoldConfigState(). Follows the project's "context owns state, component is dumb" rule. updateWingold has a state-merge bug — it spreads { ...previousValue, cfg } (storing the result under a literal cfg key) instead of { ...previousValue, ...cfg }, so the local cache isn't correctly updated after save.
  • UX notes: no list/table, no import, no print/PDF, no filters — it is a single settings form for one config record.

8. Dependencies & integrations

  • External system: WinGold — a legacy Windows jewellery/gold-trade accounting ERP. This module is intended to map zerp data to WinGold's account/code scheme for an outbound export. No transport (no HTTP client, file writer, FTP, or scheduled job) exists in this repo — only the code mapping is modeled.
  • Sync direction: one-way zerp → WinGold (export), based on the field semantics (these are codes you stamp onto outgoing records). Not bidirectional. Not live.
  • Other BE references (the only two in zerp-be):
    • zerp-be/src/modules/user/user.schema.ts:132@Prop({ default: 0 }) wingoldMemberCode: number; on the User schema (a per-user WinGold member id, defaulted to 0, not read anywhere else in BE).
    • zerp-be/src/constant.ts:7AP_WINGOLD_TIME_FORMAT = "YYYY-MM-DDThh:mm:ss" (declared, never imported).
  • No cron/jobs, no events, no S3/mail/zoom usage.

9. Gotchas & project-specific rules

  • The backend half is missing. None of Wingold (type), WingoldCommonInput (input), wingoldConfig, or updateWingoldConfig appear in zerp-be/src/schema.gql, and there is no zerp-be/src/modules/wingold. The admin module talks to an API surface that this backend does not expose — so the screen does not function against the current server. To make it work you must add a Wingold schema + resolver/service exposing those exact ops.
  • Orphaned UI. WingoldConfigPage is never routed under pages/; only its context provider is mounted. It is dead/vestigial UI.
  • No validation, free-text codes. Every WinGold code is an unvalidated string; nothing checks them against a real WinGold instance.
  • wingoldConfig is doubly-declared as both a query and a mutation with the same name in gql/query.ts; only the query path is wired into the screen. useCreateWingoldConfig is exported but unused.
  • State-merge bug in context.tsx updateWingold ({ ...previousValue, cfg } should be { ...previousValue, ...cfg }).
  • Field meanings are inferred from the WinGold domain, since there is no backend schema, no comments, and no docs in-repo. Treat the descriptions in §2 as best-effort domain inference, not code-confirmed contracts. The names themselves (Level 5 / control account / ARAP group / RP mode / salesman codes) are standard WinGold accounting terminology.
  • Bottom line: this is a stub integration — config scaffolding for a legacy WinGold export that is not implemented (and not wired) in the current codebase. Do not assume any live sync exists.