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, theWingoldtype,WingoldCommonInput) do not exist in the currentzerp-beschema.gql, and there is nowingoldmodule, resolver, service, or schema inzerp-be/src/modules. There is also nopages/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
stringcode (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"inzerp-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)
- User navigates to the Wingold Config screen →
WingoldConfigPage(page.tsx) mounts and callsfetchWingold()on mount. fetchWingold()→ context (context.tsx) runsuseLazyWingoldConfigPage→ fires thewingoldConfigquery → (would) return theWingolddocument → stored inconfigstate.- Screen renders
WingoldConfigDetailonly whenconfig?._idis truthy — so with no backend the form never renders (the guard{config?._id && <WingoldConfigDetail .../>}inpage.tsxstays false). - User edits the nine code fields and clicks Update Config →
updateWingold(values)→updateWingoldConfig(WingoldCommonInput!)mutation → on success toast "Settings Updated" and merge intoconfigstate.
Unhappy path (the current reality)
- The
wingoldConfigquery resolves against a server that has noWingoldtype / resolver, so it errors.toastSvc.graphQlError(err)surfaces the GraphQL error andconfig._idnever 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/pagesimports/rendersWingoldConfigPage. The screen component exists but is not routed (orphaned). The context provider, however, is mounted globally viazerp-admin/src/Context.tsx(WingoldConfigContextProvider, lines 44 + 108). - Title:
<ApPageTitle title="Wingold Config" />. - Form (
detail.tsx): a single Formik form with nineApTextInputs — 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 ConfigApButton(loading bound toupdateLoading).ApSwitchInput/ApTextare imported but unused. No validation (see §4). - Context methods (
context.tsx): exposesconfig,fetchWingold(),updateWingold(values),loading,updateLoadingviauseWingoldConfigState(). Follows the project's "context owns state, component is dumb" rule.updateWingoldhas a state-merge bug — it spreads{ ...previousValue, cfg }(storing the result under a literalcfgkey) 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:7—AP_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, orupdateWingoldConfigappear inzerp-be/src/schema.gql, and there is nozerp-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 aWingoldschema + resolver/service exposing those exact ops. - Orphaned UI.
WingoldConfigPageis never routed underpages/; 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.
wingoldConfigis doubly-declared as both a query and a mutation with the same name ingql/query.ts; only the query path is wired into the screen.useCreateWingoldConfigis exported but unused.- State-merge bug in
context.tsxupdateWingold({ ...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.