Add entity address/contact tables and CRUD for entity resources
This commit is contained in:
89
README.md
89
README.md
@@ -187,6 +187,78 @@ Company-scoped brands. Auth via `resolveCompanyAccess`.
|
||||
|
||||
---
|
||||
|
||||
## `customergroup`
|
||||
|
||||
Company-scoped customer groups. Auth via `resolveCompanyAccess`.
|
||||
|
||||
| Method | Signature | Returns |
|
||||
| --- | --- | --- |
|
||||
| `list` | `(googleAuthId, companyId)` | `{ id, name }[]` |
|
||||
| `create` | `(googleAuthId, companyId, { name })` | `{ id, name }` |
|
||||
| `update` | `(googleAuthId, companyId, id, { name })` | `{ id, name }` |
|
||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
||||
|
||||
Empty name → `Name required`. Deleting the POS group (or any group still referenced with `NO ACTION`) → `Customer group in use`. Cascades entities when the group is deleted. Errors: `Company not found`, `Not authorized`, `Name required`, `Customer group not found`, `Customer group in use`.
|
||||
|
||||
---
|
||||
|
||||
## `entity`
|
||||
|
||||
Entities belong to a `customergroup` of the company. Auth via `resolveCompanyAccess`.
|
||||
|
||||
| Method | Signature | Returns |
|
||||
| --- | --- | --- |
|
||||
| `list` | `(googleAuthId, companyId, { customergroupId? })` | `Entity[]` |
|
||||
| `getById` | `(googleAuthId, companyId, id)` | `Entity` |
|
||||
| `create` | `(googleAuthId, companyId, { customergroupId, name, firstName? })` | `Entity` |
|
||||
| `update` | `(googleAuthId, companyId, id, { name?, firstName? })` | `Entity` |
|
||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
||||
|
||||
```ts
|
||||
type Entity = {
|
||||
id: number,
|
||||
customergroupId: number,
|
||||
firstName: string | null,
|
||||
name: string,
|
||||
createdAt: Date,
|
||||
updatedAt: Date,
|
||||
}
|
||||
```
|
||||
|
||||
`create` / `update` write `entityhistory` (`Erstellt`, or name/firstName change lines). `customergroupId` must belong to the company. Errors: `Company not found`, `Not authorized`, `Name required`, `Customer group not found`, `Entity not found`.
|
||||
|
||||
---
|
||||
|
||||
## `entityaddress`
|
||||
|
||||
Addresses for an entity. Auth via company + entity ownership.
|
||||
|
||||
| Method | Signature | Returns |
|
||||
| --- | --- | --- |
|
||||
| `list` | `(googleAuthId, companyId, entityId)` | `EntityAddress[]` |
|
||||
| `create` | `(googleAuthId, companyId, entityId, { addressType, firstName?, name?, street?, streetNumber?, zip?, city?, county? })` | `EntityAddress` |
|
||||
| `update` | `(googleAuthId, companyId, entityId, id, patch)` | `EntityAddress` |
|
||||
| `delete` | `(googleAuthId, companyId, entityId, id)` | `void` |
|
||||
|
||||
`addressType` required. Errors: `Company not found`, `Not authorized`, `Entity not found`, `Address type required`, `Address not found`.
|
||||
|
||||
---
|
||||
|
||||
## `entitycontact`
|
||||
|
||||
Contacts for an entity (`contactType` e.g. `email`, `phone`). Auth via company + entity ownership.
|
||||
|
||||
| Method | Signature | Returns |
|
||||
| --- | --- | --- |
|
||||
| `list` | `(googleAuthId, companyId, entityId)` | `{ id, entityId, contactType, contact }[]` |
|
||||
| `create` | `(googleAuthId, companyId, entityId, { contactType, contact })` | row |
|
||||
| `update` | `(googleAuthId, companyId, entityId, id, { contactType?, contact? })` | row |
|
||||
| `delete` | `(googleAuthId, companyId, entityId, id)` | `void` |
|
||||
|
||||
Errors: `Company not found`, `Not authorized`, `Entity not found`, `Contact required`, `Contact not found`.
|
||||
|
||||
---
|
||||
|
||||
## `supplier`
|
||||
|
||||
Suppliers are `entity` rows in the company `customergroup` named `Lieferanten` (created implicitly on first supplier). Auth via `resolveCompanyAccess`.
|
||||
@@ -519,6 +591,23 @@ res.set('Content-Type', thumb.contentType).send(thumb.buffer);
|
||||
| `GET /api/brand` | `brand.list(googleAuthId, companyId)` |
|
||||
| `PUT /api/brand` | `brand.upsert(googleAuthId, companyId, { name, gsprpinfo? })` |
|
||||
| `DELETE /api/brand/:id` | `brand.delete(googleAuthId, companyId, id)` |
|
||||
| `GET /api/customergroup` | `customergroup.list(googleAuthId, companyId)` |
|
||||
| `POST /api/customergroup` | `customergroup.create(googleAuthId, companyId, { name })` |
|
||||
| `PATCH /api/customergroup/:id` | `customergroup.update(googleAuthId, companyId, id, { name })` |
|
||||
| `DELETE /api/customergroup/:id` | `customergroup.delete(googleAuthId, companyId, id)` |
|
||||
| `GET /api/entity` | `entity.list(googleAuthId, companyId, { customergroupId? })` |
|
||||
| `GET /api/entity/:id` | `entity.getById(googleAuthId, companyId, id)` |
|
||||
| `POST /api/entity` | `entity.create(googleAuthId, companyId, { customergroupId, name, firstName? })` |
|
||||
| `PATCH /api/entity/:id` | `entity.update(googleAuthId, companyId, id, { name?, firstName? })` |
|
||||
| `DELETE /api/entity/:id` | `entity.delete(googleAuthId, companyId, id)` |
|
||||
| `GET /api/entity/:entityId/address` | `entityaddress.list(googleAuthId, companyId, entityId)` |
|
||||
| `POST /api/entity/:entityId/address` | `entityaddress.create(googleAuthId, companyId, entityId, { addressType, … })` |
|
||||
| `PATCH /api/entity/:entityId/address/:id` | `entityaddress.update(googleAuthId, companyId, entityId, id, patch)` |
|
||||
| `DELETE /api/entity/:entityId/address/:id` | `entityaddress.delete(googleAuthId, companyId, entityId, id)` |
|
||||
| `GET /api/entity/:entityId/contact` | `entitycontact.list(googleAuthId, companyId, entityId)` |
|
||||
| `POST /api/entity/:entityId/contact` | `entitycontact.create(googleAuthId, companyId, entityId, { contactType, contact })` |
|
||||
| `PATCH /api/entity/:entityId/contact/:id` | `entitycontact.update(googleAuthId, companyId, entityId, id, patch)` |
|
||||
| `DELETE /api/entity/:entityId/contact/:id` | `entitycontact.delete(googleAuthId, companyId, entityId, id)` |
|
||||
| `GET /api/supplier` | `supplier.list(googleAuthId, companyId)` |
|
||||
| `POST /api/supplier` | `supplier.create(googleAuthId, companyId, { name })` |
|
||||
| `PATCH /api/supplier/:id` | `supplier.update(googleAuthId, companyId, id, { name })` |
|
||||
|
||||
@@ -275,6 +275,8 @@ const CLUSTERS = [
|
||||
'customergroup',
|
||||
'entity',
|
||||
'entityhistory',
|
||||
'entityaddress',
|
||||
'entitycontact',
|
||||
'numbers',
|
||||
],
|
||||
},
|
||||
|
||||
108
schema-graph.dot
108
schema-graph.dot
@@ -10,14 +10,16 @@ digraph schema {
|
||||
style="rounded,filled"; fillcolor="#ffffff60"; color="#a0aec0";
|
||||
fontcolor="#1a365d"; margin=14;
|
||||
customergroup [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="3" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>customergroup</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
entityaddress [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entityaddress</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="first_name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">first_name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="street" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">street?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="streetnumber" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">streetnumber?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="zip" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">zip?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="city" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">city?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="county" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">county?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="addresstype" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">addresstype</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
numbers [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>numbers</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="type" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">type</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="prefix" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">prefix</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="padding" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">padding</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="next" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">next</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
entity [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in3" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="4" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entity</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="customergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>customergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="first_name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">first_name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="updated_at" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">updated_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
company [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in3" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in4" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in5" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in6" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in7" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in8" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in9" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="10" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>company</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="default_language_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>default_language_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="root_category_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>root_category_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="poscustomergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>poscustomergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="taxrate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>taxrate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="reducedtaxrate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>reducedtaxrate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="taxfreerate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>taxfreerate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
entity [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entity</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="customergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>customergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="first_name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">first_name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="updated_at" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">updated_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
syncpos [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>syncpos</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="paircode" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">paircode</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="token" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">token?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
entitycontact [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entitycontact</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contacttype" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">contacttype</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contact" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">contact</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
meta [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>meta</B></FONT></TD></TR><TR><TD PORT="key" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">key</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="value" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">value</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
companysetting [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>companysetting</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="key" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">key</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="value" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">value</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="frontend" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">frontend</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">BIT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
entityhistory [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entityhistory</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="companyuser_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>companyuser_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="date" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">date</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="text" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">text</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
companyuser [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>companyuser</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="google_auth_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>google_auth_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
companysetting [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>companysetting</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="key" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">key</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="value" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">value</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="frontend" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">frontend</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">BIT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
google_auth [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="1" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>google_auth</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="selected_company" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>selected_company</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="email" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">email</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(320)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="picture" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">picture?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(2048)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="picturebinary" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">picturebinary?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">VARBINARY(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sub" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">sub?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
}
|
||||
subgraph cluster_i18n {
|
||||
@@ -58,9 +60,9 @@ digraph schema {
|
||||
style="rounded,filled"; fillcolor="#ffffff60"; color="#a0aec0";
|
||||
fontcolor="#1a365d"; margin=14;
|
||||
tax [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in3" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in4" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="5" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>tax</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="rate" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">rate</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DECIMAL(18,4)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
manifest [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="1" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>manifest</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="number" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">number</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="type" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">type</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="date" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">date</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
manifestarticle [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>manifestarticle</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>article_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="tax_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>tax_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="manifest_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>manifest_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="amount" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">amount</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="net" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">net</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="transactedamount" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">transactedamount</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="comment" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">comment?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="rebate" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">rebate</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
price [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>price</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>article_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="customergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>customergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="tax_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>tax_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="minmultiplier" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">minmultiplier</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DECIMAL(18,4)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="net" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">net</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
manifest [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="1" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>manifest</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="number" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">number</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="type" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">type</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="date" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">date</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
manifestarticle [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>manifestarticle</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>article_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="tax_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>tax_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="manifest_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>manifest_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="amount" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">amount</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="net" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">net</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="transactedamount" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">transactedamount</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="comment" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">comment?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="rebate" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">rebate</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
}
|
||||
subgraph cluster_units {
|
||||
label="Units"; labeljust="l"; fontsize=15;
|
||||
@@ -81,52 +83,54 @@ digraph schema {
|
||||
company:reducedtaxrate:e -> tax:in0:n [color="#c05621", fontcolor="#c05621", tooltip="FK_company_reducedtaxrate"];
|
||||
company:taxfreerate:e -> tax:in1:n [color="#319795", fontcolor="#319795", tooltip="FK_company_taxfreerate"];
|
||||
customergroup:company_id:se -> company:in3:n [color="#97266d", fontcolor="#97266d", tooltip="FK_customergroup_company"];
|
||||
company:poscustomergroup_id:nw -> customergroup:in0:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_company_poscustomergroup"];
|
||||
entity:customergroup_id:sw -> customergroup:in1:n [color="#276749", fontcolor="#276749", tooltip="FK_entity_customergroup"];
|
||||
entityhistory:entity_id:sw -> entity:in0:n [color="#9c4221", fontcolor="#9c4221", tooltip="FK_entityhistory_entity"];
|
||||
entityhistory:companyuser_id:se -> companyuser:in1:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_entityhistory_companyuser"];
|
||||
unit:company_id:e -> company:in0:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_unit_company"];
|
||||
unittext:unit_id:se -> unit:in0:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_unittext_unit"];
|
||||
unittext:language_id:se -> language:in0:n [color="#22543d", fontcolor="#22543d", tooltip="FK_unittext_language"];
|
||||
brand:company_id:e -> company:in1:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_brand_company"];
|
||||
article:unit_id:sw -> unit:in1:n [color="#702459", fontcolor="#702459", tooltip="FK_article_unit"];
|
||||
article:brand_id:e -> brand:in0:n [color="#744210", fontcolor="#744210", tooltip="FK_article_brand"];
|
||||
article:articlelist_id:sw -> articlelist:in1:n [color="#285e61", fontcolor="#285e61", tooltip="FK_article_articlelist"];
|
||||
article:optionslist_id:se -> optionslist:in0:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_article_optionslist"];
|
||||
article:fatherarticle_id:e -> article:id:e [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_article_fatherarticle"];
|
||||
articlehistory:article_id:w -> article:in5:n [color="#38a169", fontcolor="#38a169", tooltip="FK_articlehistory_article"];
|
||||
articlehistory:companyuser_id:e -> companyuser:in0:n [color="#3182ce", fontcolor="#3182ce", tooltip="FK_articlehistory_companyuser"];
|
||||
articleean:article_id:sw -> article:in3:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_articleean_article"];
|
||||
articlepic:article_id:w -> article:in7:n [color="#c53030", fontcolor="#c53030", tooltip="FK_articlepic_article"];
|
||||
articlepic:pic_id:se -> pic:in1:n [color="#2f855a", fontcolor="#2f855a", tooltip="FK_articlepic_pic"];
|
||||
brandpic:brand_id:w -> brand:in1:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_brandpic_brand"];
|
||||
brandpic:pic_id:se -> pic:in0:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_brandpic_pic"];
|
||||
articlelistarticle:articlelist_id:se -> articlelist:in0:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_articlelistarticle_articlelist"];
|
||||
articlelistarticle:article_id:se -> article:in1:n [color="#c05621", fontcolor="#c05621", tooltip="FK_articlelistarticle_article"];
|
||||
optionslistarticle:optionslist_id:sw -> optionslist:in1:n [color="#319795", fontcolor="#319795", tooltip="FK_optionslistarticle_optionslist"];
|
||||
optionslistarticle:article_id:sw -> article:in4:n [color="#97266d", fontcolor="#97266d", tooltip="FK_optionslistarticle_article"];
|
||||
categoryarticle:category_id:sw -> category:in2:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_categoryarticle_category"];
|
||||
categoryarticle:article_id:w -> article:in6:n [color="#276749", fontcolor="#276749", tooltip="FK_categoryarticle_article"];
|
||||
categorypic:category_id:sw -> category:in4:n [color="#9c4221", fontcolor="#9c4221", tooltip="FK_categorypic_category"];
|
||||
categorypic:pic_id:sw -> pic:in2:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_categorypic_pic"];
|
||||
categorytext:category_id:e -> category:in0:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_categorytext_category"];
|
||||
categorytext:language_id:sw -> language:in1:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_categorytext_language"];
|
||||
articletext:article_id:e -> article:in0:n [color="#22543d", fontcolor="#22543d", tooltip="FK_articletext_article"];
|
||||
articletext:language_id:sw -> language:in2:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_articletext_language"];
|
||||
price:tax_id:sw -> tax:in4:n [color="#702459", fontcolor="#702459", tooltip="FK_price_tax"];
|
||||
price:article_id:w -> article:in9:n [color="#744210", fontcolor="#744210", tooltip="FK_price_article"];
|
||||
price:customergroup_id:w -> customergroup:in2:n [color="#285e61", fontcolor="#285e61", tooltip="FK_price_customergroup"];
|
||||
manifest:company_id:sw -> company:in9:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_manifest_company"];
|
||||
manifest:entity_id:w -> entity:in1:n [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_manifest_entity"];
|
||||
manifestarticle:manifest_id:sw -> manifest:in0:n [color="#38a169", fontcolor="#38a169", tooltip="FK_manifestarticle_manifest"];
|
||||
manifestarticle:article_id:w -> article:in8:n [color="#3182ce", fontcolor="#3182ce", tooltip="FK_manifestarticle_article"];
|
||||
manifestarticle:tax_id:sw -> tax:in3:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_manifestarticle_tax"];
|
||||
numbers:company_id:se -> company:in4:n [color="#c53030", fontcolor="#c53030", tooltip="FK_numbers_company"];
|
||||
companyuser:google_auth_id:se -> google_auth:in0:n [color="#2f855a", fontcolor="#2f855a", tooltip="FK_companyuser_google_auth"];
|
||||
companyuser:company_id:sw -> company:in6:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_companyuser_company"];
|
||||
syncpos:company_id:sw -> company:in5:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_syncpos_company"];
|
||||
companysetting:company_id:sw -> company:in7:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_companysetting_company"];
|
||||
posterminal:company_id:e -> company:in2:n [color="#c05621", fontcolor="#c05621", tooltip="FK_posterminal_company"];
|
||||
posterminalcategory:posterminal_id:se -> posterminal:in0:n [color="#319795", fontcolor="#319795", tooltip="FK_posterminalcategory_posterminal"];
|
||||
posterminalcategory:category_id:sw -> category:in3:n [color="#97266d", fontcolor="#97266d", tooltip="FK_posterminalcategory_category"];
|
||||
company:poscustomergroup_id:nw -> customergroup:in1:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_company_poscustomergroup"];
|
||||
entity:customergroup_id:sw -> customergroup:in0:n [color="#276749", fontcolor="#276749", tooltip="FK_entity_customergroup"];
|
||||
entityaddress:entity_id:se -> entity:in0:n [color="#9c4221", fontcolor="#9c4221", tooltip="FK_entityaddress_entity"];
|
||||
entitycontact:entity_id:sw -> entity:in1:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_entitycontact_entity"];
|
||||
entityhistory:entity_id:sw -> entity:in2:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_entityhistory_entity"];
|
||||
entityhistory:companyuser_id:se -> companyuser:in1:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_entityhistory_companyuser"];
|
||||
unit:company_id:e -> company:in0:n [color="#22543d", fontcolor="#22543d", tooltip="FK_unit_company"];
|
||||
unittext:unit_id:se -> unit:in0:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_unittext_unit"];
|
||||
unittext:language_id:se -> language:in0:n [color="#702459", fontcolor="#702459", tooltip="FK_unittext_language"];
|
||||
brand:company_id:e -> company:in1:n [color="#744210", fontcolor="#744210", tooltip="FK_brand_company"];
|
||||
article:unit_id:sw -> unit:in1:n [color="#285e61", fontcolor="#285e61", tooltip="FK_article_unit"];
|
||||
article:brand_id:e -> brand:in0:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_article_brand"];
|
||||
article:articlelist_id:sw -> articlelist:in1:n [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_article_articlelist"];
|
||||
article:optionslist_id:se -> optionslist:in0:n [color="#38a169", fontcolor="#38a169", tooltip="FK_article_optionslist"];
|
||||
article:fatherarticle_id:e -> article:id:e [color="#3182ce", fontcolor="#3182ce", tooltip="FK_article_fatherarticle"];
|
||||
articlehistory:article_id:w -> article:in5:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_articlehistory_article"];
|
||||
articlehistory:companyuser_id:e -> companyuser:in0:n [color="#c53030", fontcolor="#c53030", tooltip="FK_articlehistory_companyuser"];
|
||||
articleean:article_id:sw -> article:in3:n [color="#2f855a", fontcolor="#2f855a", tooltip="FK_articleean_article"];
|
||||
articlepic:article_id:w -> article:in7:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_articlepic_article"];
|
||||
articlepic:pic_id:se -> pic:in1:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_articlepic_pic"];
|
||||
brandpic:brand_id:w -> brand:in1:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_brandpic_brand"];
|
||||
brandpic:pic_id:se -> pic:in0:n [color="#c05621", fontcolor="#c05621", tooltip="FK_brandpic_pic"];
|
||||
articlelistarticle:articlelist_id:se -> articlelist:in0:n [color="#319795", fontcolor="#319795", tooltip="FK_articlelistarticle_articlelist"];
|
||||
articlelistarticle:article_id:se -> article:in1:n [color="#97266d", fontcolor="#97266d", tooltip="FK_articlelistarticle_article"];
|
||||
optionslistarticle:optionslist_id:sw -> optionslist:in1:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_optionslistarticle_optionslist"];
|
||||
optionslistarticle:article_id:sw -> article:in4:n [color="#276749", fontcolor="#276749", tooltip="FK_optionslistarticle_article"];
|
||||
categoryarticle:category_id:sw -> category:in2:n [color="#9c4221", fontcolor="#9c4221", tooltip="FK_categoryarticle_category"];
|
||||
categoryarticle:article_id:w -> article:in6:n [color="#0987a0", fontcolor="#0987a0", tooltip="FK_categoryarticle_article"];
|
||||
categorypic:category_id:sw -> category:in4:n [color="#553c9a", fontcolor="#553c9a", tooltip="FK_categorypic_category"];
|
||||
categorypic:pic_id:sw -> pic:in2:n [color="#742a2a", fontcolor="#742a2a", tooltip="FK_categorypic_pic"];
|
||||
categorytext:category_id:e -> category:in0:n [color="#22543d", fontcolor="#22543d", tooltip="FK_categorytext_category"];
|
||||
categorytext:language_id:sw -> language:in1:n [color="#1a365d", fontcolor="#1a365d", tooltip="FK_categorytext_language"];
|
||||
articletext:article_id:e -> article:in0:n [color="#702459", fontcolor="#702459", tooltip="FK_articletext_article"];
|
||||
articletext:language_id:sw -> language:in2:n [color="#744210", fontcolor="#744210", tooltip="FK_articletext_language"];
|
||||
price:tax_id:sw -> tax:in3:n [color="#285e61", fontcolor="#285e61", tooltip="FK_price_tax"];
|
||||
price:article_id:w -> article:in8:n [color="#d53f8c", fontcolor="#d53f8c", tooltip="FK_price_article"];
|
||||
price:customergroup_id:w -> customergroup:in2:n [color="#dd6b20", fontcolor="#dd6b20", tooltip="FK_price_customergroup"];
|
||||
manifest:company_id:sw -> company:in9:n [color="#38a169", fontcolor="#38a169", tooltip="FK_manifest_company"];
|
||||
manifest:entity_id:w -> entity:in3:n [color="#3182ce", fontcolor="#3182ce", tooltip="FK_manifest_entity"];
|
||||
manifestarticle:manifest_id:sw -> manifest:in0:n [color="#805ad5", fontcolor="#805ad5", tooltip="FK_manifestarticle_manifest"];
|
||||
manifestarticle:article_id:w -> article:in9:n [color="#c53030", fontcolor="#c53030", tooltip="FK_manifestarticle_article"];
|
||||
manifestarticle:tax_id:sw -> tax:in4:n [color="#2f855a", fontcolor="#2f855a", tooltip="FK_manifestarticle_tax"];
|
||||
numbers:company_id:se -> company:in4:n [color="#2b6cb0", fontcolor="#2b6cb0", tooltip="FK_numbers_company"];
|
||||
companyuser:google_auth_id:se -> google_auth:in0:n [color="#b7791f", fontcolor="#b7791f", tooltip="FK_companyuser_google_auth"];
|
||||
companyuser:company_id:sw -> company:in7:n [color="#6b46c1", fontcolor="#6b46c1", tooltip="FK_companyuser_company"];
|
||||
syncpos:company_id:sw -> company:in5:n [color="#c05621", fontcolor="#c05621", tooltip="FK_syncpos_company"];
|
||||
companysetting:company_id:sw -> company:in6:n [color="#319795", fontcolor="#319795", tooltip="FK_companysetting_company"];
|
||||
posterminal:company_id:e -> company:in2:n [color="#97266d", fontcolor="#97266d", tooltip="FK_posterminal_company"];
|
||||
posterminalcategory:posterminal_id:se -> posterminal:in0:n [color="#4c51bf", fontcolor="#4c51bf", tooltip="FK_posterminalcategory_posterminal"];
|
||||
posterminalcategory:category_id:sw -> category:in3:n [color="#276749", fontcolor="#276749", tooltip="FK_posterminalcategory_category"];
|
||||
}
|
||||
2706
schema-graph.svg
2706
schema-graph.svg
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 180 KiB |
@@ -158,6 +158,43 @@ const MENU = {
|
||||
},
|
||||
],
|
||||
},
|
||||
customergroup: {
|
||||
label: 'customergroup',
|
||||
items: [
|
||||
{ value: 'customergroup.list', label: 'list', hint: 'googleAuthId, companyId → rows' },
|
||||
{ value: 'customergroup.create', label: 'create', hint: 'googleAuthId, companyId, name → row' },
|
||||
{ value: 'customergroup.update', label: 'update', hint: 'googleAuthId, companyId, id, name → row' },
|
||||
{ value: 'customergroup.delete', label: 'delete', hint: 'googleAuthId, companyId, id' },
|
||||
],
|
||||
},
|
||||
entity: {
|
||||
label: 'entity',
|
||||
items: [
|
||||
{ value: 'entity.list', label: 'list', hint: 'googleAuthId, companyId, customergroupId? → rows' },
|
||||
{ value: 'entity.getById', label: 'getById', hint: 'googleAuthId, companyId, id → row' },
|
||||
{ value: 'entity.create', label: 'create', hint: 'googleAuthId, companyId, JSON → row' },
|
||||
{ value: 'entity.update', label: 'update', hint: 'googleAuthId, companyId, id, JSON → row' },
|
||||
{ value: 'entity.delete', label: 'delete', hint: 'googleAuthId, companyId, id' },
|
||||
],
|
||||
},
|
||||
entityaddress: {
|
||||
label: 'entityaddress',
|
||||
items: [
|
||||
{ value: 'entityaddress.list', label: 'list', hint: 'googleAuthId, companyId, entityId → rows' },
|
||||
{ value: 'entityaddress.create', label: 'create', hint: 'googleAuthId, companyId, entityId, JSON → row' },
|
||||
{ value: 'entityaddress.update', label: 'update', hint: 'googleAuthId, companyId, entityId, id, JSON → row' },
|
||||
{ value: 'entityaddress.delete', label: 'delete', hint: 'googleAuthId, companyId, entityId, id' },
|
||||
],
|
||||
},
|
||||
entitycontact: {
|
||||
label: 'entitycontact',
|
||||
items: [
|
||||
{ value: 'entitycontact.list', label: 'list', hint: 'googleAuthId, companyId, entityId → rows' },
|
||||
{ value: 'entitycontact.create', label: 'create', hint: 'googleAuthId, companyId, entityId, JSON → row' },
|
||||
{ value: 'entitycontact.update', label: 'update', hint: 'googleAuthId, companyId, entityId, id, JSON → row' },
|
||||
{ value: 'entitycontact.delete', label: 'delete', hint: 'googleAuthId, companyId, entityId, id' },
|
||||
],
|
||||
},
|
||||
supplier: {
|
||||
label: 'supplier',
|
||||
items: [
|
||||
@@ -681,6 +718,362 @@ async function runMethod(client, action) {
|
||||
await client.brand.delete(Number(googleAuthId), Number(companyId), id);
|
||||
return ['ok', true];
|
||||
}
|
||||
case 'customergroup.list': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
return [
|
||||
'result[]',
|
||||
await client.customergroup.list(Number(googleAuthId), Number(companyId)),
|
||||
];
|
||||
}
|
||||
case 'customergroup.create': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const name = await askText('name', {
|
||||
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
||||
});
|
||||
if (name == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.customergroup.create(Number(googleAuthId), Number(companyId), {
|
||||
name,
|
||||
}),
|
||||
];
|
||||
}
|
||||
case 'customergroup.update': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const id = await askInt('customergroup id');
|
||||
if (id == null) return;
|
||||
const name = await askText('name', {
|
||||
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
||||
});
|
||||
if (name == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.customergroup.update(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(id),
|
||||
{ name },
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'customergroup.delete': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const id = await askInt('customergroup id');
|
||||
if (id == null) return;
|
||||
await client.customergroup.delete(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(id),
|
||||
);
|
||||
return ['ok', true];
|
||||
}
|
||||
case 'entity.list': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const groupRaw = await askText('customergroup id (empty = all)', {
|
||||
placeholder: '',
|
||||
validate: (v) =>
|
||||
v?.trim() && !/^\d+$/.test(v.trim()) ? 'Integer or empty' : undefined,
|
||||
});
|
||||
if (groupRaw == null) return;
|
||||
const customergroupId = groupRaw.trim()
|
||||
? Number(groupRaw.trim())
|
||||
: undefined;
|
||||
return [
|
||||
'result[]',
|
||||
await client.entity.list(Number(googleAuthId), Number(companyId), {
|
||||
customergroupId,
|
||||
}),
|
||||
];
|
||||
}
|
||||
case 'entity.getById': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const id = await askInt('entity id');
|
||||
if (id == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.entity.getById(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(id),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entity.create': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const bodyJson = await askText('entity JSON', {
|
||||
placeholder: '{"customergroupId":1,"name":"Acme","firstName":null}',
|
||||
validate: (v) => {
|
||||
if (!v?.trim()) return 'Required';
|
||||
try {
|
||||
JSON.parse(v);
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
},
|
||||
});
|
||||
if (bodyJson == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.entity.create(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
JSON.parse(bodyJson),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entity.update': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const id = await askInt('entity id');
|
||||
if (id == null) return;
|
||||
const patchJson = await askText('patch JSON', {
|
||||
placeholder: '{"name":"Acme","firstName":"Ada"}',
|
||||
validate: (v) => {
|
||||
if (!v?.trim()) return 'Required';
|
||||
try {
|
||||
JSON.parse(v);
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
},
|
||||
});
|
||||
if (patchJson == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.entity.update(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(id),
|
||||
JSON.parse(patchJson),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entity.delete': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const id = await askInt('entity id');
|
||||
if (id == null) return;
|
||||
await client.entity.delete(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(id),
|
||||
);
|
||||
return ['ok', true];
|
||||
}
|
||||
case 'entityaddress.list': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
return [
|
||||
'result[]',
|
||||
await client.entityaddress.list(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entityaddress.create': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
const bodyJson = await askText('address JSON', {
|
||||
placeholder:
|
||||
'{"addressType":"billing","street":"Main","streetNumber":"1","zip":"1010","city":"Wien"}',
|
||||
validate: (v) => {
|
||||
if (!v?.trim()) return 'Required';
|
||||
try {
|
||||
JSON.parse(v);
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
},
|
||||
});
|
||||
if (bodyJson == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.entityaddress.create(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
JSON.parse(bodyJson),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entityaddress.update': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
const id = await askInt('address id');
|
||||
if (id == null) return;
|
||||
const patchJson = await askText('patch JSON', {
|
||||
placeholder: '{"city":"Graz"}',
|
||||
validate: (v) => {
|
||||
if (!v?.trim()) return 'Required';
|
||||
try {
|
||||
JSON.parse(v);
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
},
|
||||
});
|
||||
if (patchJson == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.entityaddress.update(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
Number(id),
|
||||
JSON.parse(patchJson),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entityaddress.delete': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
const id = await askInt('address id');
|
||||
if (id == null) return;
|
||||
await client.entityaddress.delete(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
Number(id),
|
||||
);
|
||||
return ['ok', true];
|
||||
}
|
||||
case 'entitycontact.list': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
return [
|
||||
'result[]',
|
||||
await client.entitycontact.list(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entitycontact.create': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
const bodyJson = await askText('contact JSON', {
|
||||
placeholder: '{"contactType":"email","contact":"a@b.c"}',
|
||||
validate: (v) => {
|
||||
if (!v?.trim()) return 'Required';
|
||||
try {
|
||||
JSON.parse(v);
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
},
|
||||
});
|
||||
if (bodyJson == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.entitycontact.create(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
JSON.parse(bodyJson),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entitycontact.update': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
const id = await askInt('contact id');
|
||||
if (id == null) return;
|
||||
const patchJson = await askText('patch JSON', {
|
||||
placeholder: '{"contact":"b@c.d"}',
|
||||
validate: (v) => {
|
||||
if (!v?.trim()) return 'Required';
|
||||
try {
|
||||
JSON.parse(v);
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
},
|
||||
});
|
||||
if (patchJson == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.entitycontact.update(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
Number(id),
|
||||
JSON.parse(patchJson),
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'entitycontact.delete': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const entityId = await askInt('entity id');
|
||||
if (entityId == null) return;
|
||||
const id = await askInt('contact id');
|
||||
if (id == null) return;
|
||||
await client.entitycontact.delete(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
Number(entityId),
|
||||
Number(id),
|
||||
);
|
||||
return ['ok', true];
|
||||
}
|
||||
case 'supplier.list': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
|
||||
46
src/index.js
46
src/index.js
@@ -39,6 +39,23 @@ import companysettingDelete from './store/companysetting/delete.js';
|
||||
import brandList from './store/brand/list.js';
|
||||
import brandUpsert from './store/brand/upsert.js';
|
||||
import brandDelete from './store/brand/delete.js';
|
||||
import customergroupList from './store/customergroup/list.js';
|
||||
import customergroupCreate from './store/customergroup/create.js';
|
||||
import customergroupUpdate from './store/customergroup/update.js';
|
||||
import customergroupDelete from './store/customergroup/delete.js';
|
||||
import entityList from './store/entity/list.js';
|
||||
import entityGetById from './store/entity/getById.js';
|
||||
import entityCreate from './store/entity/create.js';
|
||||
import entityUpdate from './store/entity/update.js';
|
||||
import entityDelete from './store/entity/delete.js';
|
||||
import entityaddressList from './store/entityaddress/list.js';
|
||||
import entityaddressCreate from './store/entityaddress/create.js';
|
||||
import entityaddressUpdate from './store/entityaddress/update.js';
|
||||
import entityaddressDelete from './store/entityaddress/delete.js';
|
||||
import entitycontactList from './store/entitycontact/list.js';
|
||||
import entitycontactCreate from './store/entitycontact/create.js';
|
||||
import entitycontactUpdate from './store/entitycontact/update.js';
|
||||
import entitycontactDelete from './store/entitycontact/delete.js';
|
||||
import supplierList from './store/supplier/list.js';
|
||||
import supplierCreate from './store/supplier/create.js';
|
||||
import supplierUpdate from './store/supplier/update.js';
|
||||
@@ -158,6 +175,35 @@ export default class LibDashStore {
|
||||
delete: brandDelete(pool),
|
||||
};
|
||||
|
||||
this.customergroup = {
|
||||
list: customergroupList(pool),
|
||||
create: customergroupCreate(pool),
|
||||
update: customergroupUpdate(pool),
|
||||
delete: customergroupDelete(pool),
|
||||
};
|
||||
|
||||
this.entity = {
|
||||
list: entityList(pool),
|
||||
getById: entityGetById(pool),
|
||||
create: entityCreate(pool),
|
||||
update: entityUpdate(pool),
|
||||
delete: entityDelete(pool),
|
||||
};
|
||||
|
||||
this.entityaddress = {
|
||||
list: entityaddressList(pool),
|
||||
create: entityaddressCreate(pool),
|
||||
update: entityaddressUpdate(pool),
|
||||
delete: entityaddressDelete(pool),
|
||||
};
|
||||
|
||||
this.entitycontact = {
|
||||
list: entitycontactList(pool),
|
||||
create: entitycontactCreate(pool),
|
||||
update: entitycontactUpdate(pool),
|
||||
delete: entitycontactDelete(pool),
|
||||
};
|
||||
|
||||
this.supplier = {
|
||||
list: supplierList(pool),
|
||||
create: supplierCreate(pool),
|
||||
|
||||
@@ -164,6 +164,38 @@ BEGIN
|
||||
END
|
||||
`;
|
||||
|
||||
export const INIT_ENTITYADDRESS = `
|
||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'entityaddress')
|
||||
BEGIN
|
||||
CREATE TABLE entityaddress (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
entity_id INT NOT NULL,
|
||||
first_name NVARCHAR(255) NULL,
|
||||
name NVARCHAR(255) NULL,
|
||||
street NVARCHAR(255) NULL,
|
||||
streetnumber NVARCHAR(50) NULL,
|
||||
zip NVARCHAR(50) NULL,
|
||||
city NVARCHAR(255) NULL,
|
||||
county NVARCHAR(255) NULL,
|
||||
addresstype NVARCHAR(50) NOT NULL,
|
||||
CONSTRAINT FK_entityaddress_entity FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE
|
||||
);
|
||||
END
|
||||
`;
|
||||
|
||||
export const INIT_ENTITYCONTACT = `
|
||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'entitycontact')
|
||||
BEGIN
|
||||
CREATE TABLE entitycontact (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
entity_id INT NOT NULL,
|
||||
contacttype NVARCHAR(50) NOT NULL,
|
||||
contact NVARCHAR(255) NOT NULL,
|
||||
CONSTRAINT FK_entitycontact_entity FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE
|
||||
);
|
||||
END
|
||||
`;
|
||||
|
||||
export const INIT_ENTITYHISTORY = `
|
||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'entityhistory')
|
||||
BEGIN
|
||||
@@ -636,6 +668,8 @@ export const SCHEMA_SCRIPTS = [
|
||||
INIT_CUSTOMERGROUP,
|
||||
INIT_COMPANY_POS_CUSTOMERGROUP_FK,
|
||||
INIT_ENTITY,
|
||||
INIT_ENTITYADDRESS,
|
||||
INIT_ENTITYCONTACT,
|
||||
INIT_UNIT,
|
||||
INIT_UNITTEXT,
|
||||
INIT_OPTIONSLIST,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const CREATE = `
|
||||
INSERT INTO customergroup (name, company_id)
|
||||
OUTPUT INSERTED.id
|
||||
OUTPUT INSERTED.id, INSERTED.name
|
||||
VALUES (@name, @companyId)
|
||||
`;
|
||||
|
||||
@@ -17,7 +17,32 @@ WHERE id = @id
|
||||
`;
|
||||
|
||||
export const GET_BY_COMPANY_AND_NAME = `
|
||||
SELECT id
|
||||
SELECT id, name
|
||||
FROM customergroup
|
||||
WHERE company_id = @companyId AND name = @name
|
||||
`;
|
||||
|
||||
export const LIST_BY_COMPANY = `
|
||||
SELECT id, name
|
||||
FROM customergroup
|
||||
WHERE company_id = @companyId
|
||||
ORDER BY name, id
|
||||
`;
|
||||
|
||||
export const GET_BY_COMPANY_AND_ID = `
|
||||
SELECT id, name
|
||||
FROM customergroup
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
export const UPDATE_NAME = `
|
||||
UPDATE customergroup
|
||||
SET name = @name
|
||||
OUTPUT INSERTED.id, INSERTED.name
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
export const DELETE_BY_COMPANY_AND_ID = `
|
||||
DELETE FROM customergroup
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
@@ -1,5 +1,42 @@
|
||||
export const SUPPLIER_GROUP_NAME = 'Lieferanten';
|
||||
|
||||
export const ENTITY_COLUMNS = `
|
||||
e.id,
|
||||
e.customergroup_id AS customergroupId,
|
||||
e.first_name AS firstName,
|
||||
e.name,
|
||||
e.created_at AS createdAt,
|
||||
e.updated_at AS updatedAt
|
||||
`;
|
||||
|
||||
export const LIST_BY_COMPANY = `
|
||||
SELECT
|
||||
${ENTITY_COLUMNS}
|
||||
FROM entity e
|
||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||
WHERE cg.company_id = @companyId
|
||||
ORDER BY e.name, e.id
|
||||
`;
|
||||
|
||||
export const LIST_BY_COMPANY_AND_GROUP = `
|
||||
SELECT
|
||||
${ENTITY_COLUMNS}
|
||||
FROM entity e
|
||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||
WHERE cg.company_id = @companyId
|
||||
AND e.customergroup_id = @customergroupId
|
||||
ORDER BY e.name, e.id
|
||||
`;
|
||||
|
||||
export const GET_BY_COMPANY_AND_ID = `
|
||||
SELECT
|
||||
${ENTITY_COLUMNS}
|
||||
FROM entity e
|
||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||
WHERE e.id = @id
|
||||
AND cg.company_id = @companyId
|
||||
`;
|
||||
|
||||
export const LIST_SUPPLIERS_BY_COMPANY = `
|
||||
SELECT
|
||||
e.id,
|
||||
@@ -27,9 +64,31 @@ WHERE e.id = @id
|
||||
`;
|
||||
|
||||
export const CREATE = `
|
||||
INSERT INTO entity (customergroup_id, name)
|
||||
OUTPUT INSERTED.id, INSERTED.name, INSERTED.created_at AS createdAt, INSERTED.updated_at AS updatedAt
|
||||
VALUES (@customergroupId, @name)
|
||||
INSERT INTO entity (customergroup_id, first_name, name)
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.customergroup_id AS customergroupId,
|
||||
INSERTED.first_name AS firstName,
|
||||
INSERTED.name,
|
||||
INSERTED.created_at AS createdAt,
|
||||
INSERTED.updated_at AS updatedAt
|
||||
VALUES (@customergroupId, @firstName, @name)
|
||||
`;
|
||||
|
||||
export const UPDATE = `
|
||||
UPDATE entity
|
||||
SET
|
||||
first_name = @firstName,
|
||||
name = @name,
|
||||
updated_at = SYSUTCDATETIME()
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.customergroup_id AS customergroupId,
|
||||
INSERTED.first_name AS firstName,
|
||||
INSERTED.name,
|
||||
INSERTED.created_at AS createdAt,
|
||||
INSERTED.updated_at AS updatedAt
|
||||
WHERE id = @id
|
||||
`;
|
||||
|
||||
export const UPDATE_NAME = `
|
||||
@@ -40,6 +99,14 @@ WHERE id = @id
|
||||
AND customergroup_id = @customergroupId
|
||||
`;
|
||||
|
||||
export const DELETE_BY_COMPANY_AND_ID = `
|
||||
DELETE e
|
||||
FROM entity e
|
||||
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||
WHERE e.id = @id
|
||||
AND cg.company_id = @companyId
|
||||
`;
|
||||
|
||||
export const DELETE_BY_ID = `
|
||||
DELETE e
|
||||
FROM entity e
|
||||
|
||||
93
src/sql/entityaddress.js
Normal file
93
src/sql/entityaddress.js
Normal file
@@ -0,0 +1,93 @@
|
||||
export const ADDRESS_COLUMNS = `
|
||||
id,
|
||||
entity_id AS entityId,
|
||||
first_name AS firstName,
|
||||
name,
|
||||
street,
|
||||
streetnumber AS streetNumber,
|
||||
zip,
|
||||
city,
|
||||
county,
|
||||
addresstype AS addressType
|
||||
`;
|
||||
|
||||
export const LIST_BY_ENTITY = `
|
||||
SELECT
|
||||
${ADDRESS_COLUMNS}
|
||||
FROM entityaddress
|
||||
WHERE entity_id = @entityId
|
||||
ORDER BY id
|
||||
`;
|
||||
|
||||
export const GET_BY_ENTITY_AND_ID = `
|
||||
SELECT
|
||||
${ADDRESS_COLUMNS}
|
||||
FROM entityaddress
|
||||
WHERE id = @id AND entity_id = @entityId
|
||||
`;
|
||||
|
||||
export const CREATE = `
|
||||
INSERT INTO entityaddress (
|
||||
entity_id,
|
||||
first_name,
|
||||
name,
|
||||
street,
|
||||
streetnumber,
|
||||
zip,
|
||||
city,
|
||||
county,
|
||||
addresstype
|
||||
)
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.entity_id AS entityId,
|
||||
INSERTED.first_name AS firstName,
|
||||
INSERTED.name,
|
||||
INSERTED.street,
|
||||
INSERTED.streetnumber AS streetNumber,
|
||||
INSERTED.zip,
|
||||
INSERTED.city,
|
||||
INSERTED.county,
|
||||
INSERTED.addresstype AS addressType
|
||||
VALUES (
|
||||
@entityId,
|
||||
@firstName,
|
||||
@name,
|
||||
@street,
|
||||
@streetNumber,
|
||||
@zip,
|
||||
@city,
|
||||
@county,
|
||||
@addressType
|
||||
)
|
||||
`;
|
||||
|
||||
export const UPDATE = `
|
||||
UPDATE entityaddress
|
||||
SET
|
||||
first_name = @firstName,
|
||||
name = @name,
|
||||
street = @street,
|
||||
streetnumber = @streetNumber,
|
||||
zip = @zip,
|
||||
city = @city,
|
||||
county = @county,
|
||||
addresstype = @addressType
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.entity_id AS entityId,
|
||||
INSERTED.first_name AS firstName,
|
||||
INSERTED.name,
|
||||
INSERTED.street,
|
||||
INSERTED.streetnumber AS streetNumber,
|
||||
INSERTED.zip,
|
||||
INSERTED.city,
|
||||
INSERTED.county,
|
||||
INSERTED.addresstype AS addressType
|
||||
WHERE id = @id AND entity_id = @entityId
|
||||
`;
|
||||
|
||||
export const DELETE_BY_ENTITY_AND_ID = `
|
||||
DELETE FROM entityaddress
|
||||
WHERE id = @id AND entity_id = @entityId
|
||||
`;
|
||||
47
src/sql/entitycontact.js
Normal file
47
src/sql/entitycontact.js
Normal file
@@ -0,0 +1,47 @@
|
||||
export const CONTACT_COLUMNS = `
|
||||
id,
|
||||
entity_id AS entityId,
|
||||
contacttype AS contactType,
|
||||
contact
|
||||
`;
|
||||
|
||||
export const LIST_BY_ENTITY = `
|
||||
SELECT
|
||||
${CONTACT_COLUMNS}
|
||||
FROM entitycontact
|
||||
WHERE entity_id = @entityId
|
||||
ORDER BY id
|
||||
`;
|
||||
|
||||
export const GET_BY_ENTITY_AND_ID = `
|
||||
SELECT
|
||||
${CONTACT_COLUMNS}
|
||||
FROM entitycontact
|
||||
WHERE id = @id AND entity_id = @entityId
|
||||
`;
|
||||
|
||||
export const CREATE = `
|
||||
INSERT INTO entitycontact (entity_id, contacttype, contact)
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.entity_id AS entityId,
|
||||
INSERTED.contacttype AS contactType,
|
||||
INSERTED.contact
|
||||
VALUES (@entityId, @contactType, @contact)
|
||||
`;
|
||||
|
||||
export const UPDATE = `
|
||||
UPDATE entitycontact
|
||||
SET contacttype = @contactType, contact = @contact
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.entity_id AS entityId,
|
||||
INSERTED.contacttype AS contactType,
|
||||
INSERTED.contact
|
||||
WHERE id = @id AND entity_id = @entityId
|
||||
`;
|
||||
|
||||
export const DELETE_BY_ENTITY_AND_ID = `
|
||||
DELETE FROM entitycontact
|
||||
WHERE id = @id AND entity_id = @entityId
|
||||
`;
|
||||
@@ -20,6 +20,8 @@ export const TABLES = [
|
||||
'articleean',
|
||||
'articlehistory',
|
||||
'entityhistory',
|
||||
'entityaddress',
|
||||
'entitycontact',
|
||||
'article',
|
||||
'brand',
|
||||
'articlelist',
|
||||
|
||||
24
src/store/customergroup/create.js
Normal file
24
src/store/customergroup/create.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { CREATE } from '../../sql/customergroup.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
export default function create(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, { name } = {}) => {
|
||||
const cleaned = name?.trim();
|
||||
if (!cleaned) {
|
||||
throw new Error('Name required');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.input('name', cleaned)
|
||||
.query(CREATE);
|
||||
|
||||
const row = result.recordset[0];
|
||||
return { id: row.id, name: row.name };
|
||||
};
|
||||
}
|
||||
31
src/store/customergroup/delete.js
Normal file
31
src/store/customergroup/delete.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/customergroup.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
export default function del(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, id) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
try {
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('companyId', companyId)
|
||||
.query(DELETE_BY_COMPANY_AND_ID);
|
||||
|
||||
if (!result.rowsAffected[0]) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.number === 547) {
|
||||
throw new Error('Customer group in use');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
20
src/store/customergroup/list.js
Normal file
20
src/store/customergroup/list.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { LIST_BY_COMPANY } from '../../sql/customergroup.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
export default function list(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId) => {
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.query(LIST_BY_COMPANY);
|
||||
|
||||
return result.recordset.map((row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
}));
|
||||
};
|
||||
}
|
||||
22
src/store/customergroup/resolveCustomerGroupAccess.js
Normal file
22
src/store/customergroup/resolveCustomerGroupAccess.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { GET_BY_COMPANY_AND_ID } from '../../sql/customergroup.js';
|
||||
import request from '../request.js';
|
||||
|
||||
/** Ensure customergroup belongs to company. Throws Customer group not found. */
|
||||
export default function resolveCustomerGroupAccess(pool) {
|
||||
return async (companyId, customergroupId, tx) => {
|
||||
if (!Number.isFinite(customergroupId)) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
|
||||
const result = await request(pool, tx)
|
||||
.input('id', customergroupId)
|
||||
.input('companyId', companyId)
|
||||
.query(GET_BY_COMPANY_AND_ID);
|
||||
|
||||
const row = result.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
return row;
|
||||
};
|
||||
}
|
||||
32
src/store/customergroup/update.js
Normal file
32
src/store/customergroup/update.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { UPDATE_NAME } from '../../sql/customergroup.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
export default function update(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, id, { name } = {}) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
|
||||
const cleaned = name?.trim();
|
||||
if (!cleaned) {
|
||||
throw new Error('Name required');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('companyId', companyId)
|
||||
.input('name', cleaned)
|
||||
.query(UPDATE_NAME);
|
||||
|
||||
const row = result.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
return { id: row.id, name: row.name };
|
||||
};
|
||||
}
|
||||
69
src/store/entity/create.js
Normal file
69
src/store/entity/create.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import { CREATE } from '../../sql/entity.js';
|
||||
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
||||
import request from '../request.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveCustomerGroupAccess from '../customergroup/resolveCustomerGroupAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
customergroupId: row.customergroupId,
|
||||
firstName: row.firstName ?? null,
|
||||
name: row.name,
|
||||
createdAt: row.createdAt,
|
||||
updatedAt: row.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export default function create(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const groupAccess = resolveCustomerGroupAccess(pool);
|
||||
|
||||
return async (
|
||||
googleAuthId,
|
||||
companyId,
|
||||
{ customergroupId, name, firstName = null } = {},
|
||||
) => {
|
||||
const cleaned = name?.trim();
|
||||
if (!cleaned) {
|
||||
throw new Error('Name required');
|
||||
}
|
||||
|
||||
const first =
|
||||
firstName == null || firstName === ''
|
||||
? null
|
||||
: String(firstName).trim() || null;
|
||||
|
||||
const { companyuserId } = await access(googleAuthId, companyId);
|
||||
await groupAccess(companyId, customergroupId);
|
||||
|
||||
const tx = pool.transaction();
|
||||
await tx.begin();
|
||||
|
||||
try {
|
||||
const created = await request(pool, tx)
|
||||
.input('customergroupId', customergroupId)
|
||||
.input('firstName', first)
|
||||
.input('name', cleaned)
|
||||
.query(CREATE);
|
||||
|
||||
const row = created.recordset[0];
|
||||
|
||||
await request(pool, tx)
|
||||
.input('entityId', row.id)
|
||||
.input('companyuserId', companyuserId)
|
||||
.input('text', 'Erstellt')
|
||||
.query(INSERT_HISTORY);
|
||||
|
||||
await tx.commit();
|
||||
return shape(row);
|
||||
} catch (err) {
|
||||
try {
|
||||
await tx.rollback();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
24
src/store/entity/delete.js
Normal file
24
src/store/entity/delete.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/entity.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
export default function del(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, id) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('companyId', companyId)
|
||||
.query(DELETE_BY_COMPANY_AND_ID);
|
||||
|
||||
if (!result.rowsAffected[0]) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
};
|
||||
}
|
||||
37
src/store/entity/getById.js
Normal file
37
src/store/entity/getById.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { GET_BY_COMPANY_AND_ID } from '../../sql/entity.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
customergroupId: row.customergroupId,
|
||||
firstName: row.firstName ?? null,
|
||||
name: row.name,
|
||||
createdAt: row.createdAt,
|
||||
updatedAt: row.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export default function getById(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, id) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('companyId', companyId)
|
||||
.query(GET_BY_COMPANY_AND_ID);
|
||||
|
||||
const row = result.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
return shape(row);
|
||||
};
|
||||
}
|
||||
43
src/store/entity/list.js
Normal file
43
src/store/entity/list.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
LIST_BY_COMPANY,
|
||||
LIST_BY_COMPANY_AND_GROUP,
|
||||
} from '../../sql/entity.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveCustomerGroupAccess from '../customergroup/resolveCustomerGroupAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
customergroupId: row.customergroupId,
|
||||
firstName: row.firstName ?? null,
|
||||
name: row.name,
|
||||
createdAt: row.createdAt,
|
||||
updatedAt: row.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export default function list(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const groupAccess = resolveCustomerGroupAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, { customergroupId } = {}) => {
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
if (customergroupId != null) {
|
||||
await groupAccess(companyId, customergroupId);
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.input('customergroupId', customergroupId)
|
||||
.query(LIST_BY_COMPANY_AND_GROUP);
|
||||
return result.recordset.map(shape);
|
||||
}
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.query(LIST_BY_COMPANY);
|
||||
|
||||
return result.recordset.map(shape);
|
||||
};
|
||||
}
|
||||
22
src/store/entity/resolveEntityAccess.js
Normal file
22
src/store/entity/resolveEntityAccess.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { GET_BY_COMPANY_AND_ID } from '../../sql/entity.js';
|
||||
import request from '../request.js';
|
||||
|
||||
/** Ensure entity belongs to company. Throws Entity not found. */
|
||||
export default function resolveEntityAccess(pool) {
|
||||
return async (companyId, entityId, tx) => {
|
||||
if (!Number.isFinite(entityId)) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
|
||||
const result = await request(pool, tx)
|
||||
.input('id', entityId)
|
||||
.input('companyId', companyId)
|
||||
.query(GET_BY_COMPANY_AND_ID);
|
||||
|
||||
const row = result.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
return row;
|
||||
};
|
||||
}
|
||||
110
src/store/entity/update.js
Normal file
110
src/store/entity/update.js
Normal file
@@ -0,0 +1,110 @@
|
||||
import { GET_BY_COMPANY_AND_ID, UPDATE } from '../../sql/entity.js';
|
||||
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
||||
import request from '../request.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
customergroupId: row.customergroupId,
|
||||
firstName: row.firstName ?? null,
|
||||
name: row.name,
|
||||
createdAt: row.createdAt,
|
||||
updatedAt: row.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export default function update(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, id, patch = {}) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
|
||||
const hasName = Object.prototype.hasOwnProperty.call(patch, 'name');
|
||||
const hasFirstName = Object.prototype.hasOwnProperty.call(patch, 'firstName');
|
||||
if (!hasName && !hasFirstName) {
|
||||
throw new Error('Name required');
|
||||
}
|
||||
|
||||
const { companyuserId } = await access(googleAuthId, companyId);
|
||||
|
||||
const existing = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('companyId', companyId)
|
||||
.query(GET_BY_COMPANY_AND_ID);
|
||||
|
||||
const current = existing.recordset[0];
|
||||
if (!current) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
|
||||
let name = current.name;
|
||||
if (hasName) {
|
||||
name = patch.name?.trim();
|
||||
if (!name) {
|
||||
throw new Error('Name required');
|
||||
}
|
||||
}
|
||||
|
||||
let firstName = current.firstName ?? null;
|
||||
if (hasFirstName) {
|
||||
firstName =
|
||||
patch.firstName == null || patch.firstName === ''
|
||||
? null
|
||||
: String(patch.firstName).trim() || null;
|
||||
}
|
||||
|
||||
const historyLines = [];
|
||||
const oldFirst = current.firstName ?? '';
|
||||
const newFirst = firstName ?? '';
|
||||
if (oldFirst !== newFirst) {
|
||||
historyLines.push(
|
||||
`Vorname geändert von "${oldFirst}" auf "${newFirst}"`,
|
||||
);
|
||||
}
|
||||
if (current.name !== name) {
|
||||
historyLines.push(
|
||||
`Name geändert von "${current.name}" auf "${name}"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!historyLines.length) {
|
||||
return shape(current);
|
||||
}
|
||||
|
||||
const tx = pool.transaction();
|
||||
await tx.begin();
|
||||
|
||||
try {
|
||||
const updated = await request(pool, tx)
|
||||
.input('id', id)
|
||||
.input('firstName', firstName)
|
||||
.input('name', name)
|
||||
.query(UPDATE);
|
||||
|
||||
const row = updated.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Entity not found');
|
||||
}
|
||||
|
||||
await request(pool, tx)
|
||||
.input('entityId', id)
|
||||
.input('companyuserId', companyuserId)
|
||||
.input('text', historyLines.join('\n'))
|
||||
.query(INSERT_HISTORY);
|
||||
|
||||
await tx.commit();
|
||||
return shape(row);
|
||||
} catch (err) {
|
||||
try {
|
||||
await tx.rollback();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
56
src/store/entityaddress/create.js
Normal file
56
src/store/entityaddress/create.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { CREATE } from '../../sql/entityaddress.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
entityId: row.entityId,
|
||||
firstName: row.firstName ?? null,
|
||||
name: row.name ?? null,
|
||||
street: row.street ?? null,
|
||||
streetNumber: row.streetNumber ?? null,
|
||||
zip: row.zip ?? null,
|
||||
city: row.city ?? null,
|
||||
county: row.county ?? null,
|
||||
addressType: row.addressType,
|
||||
};
|
||||
}
|
||||
|
||||
function optionalString(value) {
|
||||
if (value == null || value === '') return null;
|
||||
const s = String(value).trim();
|
||||
return s || null;
|
||||
}
|
||||
|
||||
export default function create(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId, input = {}) => {
|
||||
const addressType = input.addressType?.trim?.()
|
||||
? input.addressType.trim()
|
||||
: null;
|
||||
if (!addressType) {
|
||||
throw new Error('Address type required');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('entityId', entityId)
|
||||
.input('firstName', optionalString(input.firstName))
|
||||
.input('name', optionalString(input.name))
|
||||
.input('street', optionalString(input.street))
|
||||
.input('streetNumber', optionalString(input.streetNumber))
|
||||
.input('zip', optionalString(input.zip))
|
||||
.input('city', optionalString(input.city))
|
||||
.input('county', optionalString(input.county))
|
||||
.input('addressType', addressType)
|
||||
.query(CREATE);
|
||||
|
||||
return shape(result.recordset[0]);
|
||||
};
|
||||
}
|
||||
27
src/store/entityaddress/delete.js
Normal file
27
src/store/entityaddress/delete.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { DELETE_BY_ENTITY_AND_ID } from '../../sql/entityaddress.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
export default function del(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId, id) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Address not found');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('entityId', entityId)
|
||||
.query(DELETE_BY_ENTITY_AND_ID);
|
||||
|
||||
if (!result.rowsAffected[0]) {
|
||||
throw new Error('Address not found');
|
||||
}
|
||||
};
|
||||
}
|
||||
35
src/store/entityaddress/list.js
Normal file
35
src/store/entityaddress/list.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { LIST_BY_ENTITY } from '../../sql/entityaddress.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
entityId: row.entityId,
|
||||
firstName: row.firstName ?? null,
|
||||
name: row.name ?? null,
|
||||
street: row.street ?? null,
|
||||
streetNumber: row.streetNumber ?? null,
|
||||
zip: row.zip ?? null,
|
||||
city: row.city ?? null,
|
||||
county: row.county ?? null,
|
||||
addressType: row.addressType,
|
||||
};
|
||||
}
|
||||
|
||||
export default function list(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId) => {
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('entityId', entityId)
|
||||
.query(LIST_BY_ENTITY);
|
||||
|
||||
return result.recordset.map(shape);
|
||||
};
|
||||
}
|
||||
104
src/store/entityaddress/update.js
Normal file
104
src/store/entityaddress/update.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import { GET_BY_ENTITY_AND_ID, UPDATE } from '../../sql/entityaddress.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
entityId: row.entityId,
|
||||
firstName: row.firstName ?? null,
|
||||
name: row.name ?? null,
|
||||
street: row.street ?? null,
|
||||
streetNumber: row.streetNumber ?? null,
|
||||
zip: row.zip ?? null,
|
||||
city: row.city ?? null,
|
||||
county: row.county ?? null,
|
||||
addressType: row.addressType,
|
||||
};
|
||||
}
|
||||
|
||||
function optionalString(value) {
|
||||
if (value == null || value === '') return null;
|
||||
const s = String(value).trim();
|
||||
return s || null;
|
||||
}
|
||||
|
||||
export default function update(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId, id, patch = {}) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Address not found');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const existing = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('entityId', entityId)
|
||||
.query(GET_BY_ENTITY_AND_ID);
|
||||
|
||||
const current = existing.recordset[0];
|
||||
if (!current) {
|
||||
throw new Error('Address not found');
|
||||
}
|
||||
|
||||
const firstName = Object.prototype.hasOwnProperty.call(patch, 'firstName')
|
||||
? optionalString(patch.firstName)
|
||||
: current.firstName ?? null;
|
||||
const name = Object.prototype.hasOwnProperty.call(patch, 'name')
|
||||
? optionalString(patch.name)
|
||||
: current.name ?? null;
|
||||
const street = Object.prototype.hasOwnProperty.call(patch, 'street')
|
||||
? optionalString(patch.street)
|
||||
: current.street ?? null;
|
||||
const streetNumber = Object.prototype.hasOwnProperty.call(
|
||||
patch,
|
||||
'streetNumber',
|
||||
)
|
||||
? optionalString(patch.streetNumber)
|
||||
: current.streetNumber ?? null;
|
||||
const zip = Object.prototype.hasOwnProperty.call(patch, 'zip')
|
||||
? optionalString(patch.zip)
|
||||
: current.zip ?? null;
|
||||
const city = Object.prototype.hasOwnProperty.call(patch, 'city')
|
||||
? optionalString(patch.city)
|
||||
: current.city ?? null;
|
||||
const county = Object.prototype.hasOwnProperty.call(patch, 'county')
|
||||
? optionalString(patch.county)
|
||||
: current.county ?? null;
|
||||
|
||||
let addressType = current.addressType;
|
||||
if (Object.prototype.hasOwnProperty.call(patch, 'addressType')) {
|
||||
addressType = patch.addressType?.trim?.()
|
||||
? patch.addressType.trim()
|
||||
: null;
|
||||
if (!addressType) {
|
||||
throw new Error('Address type required');
|
||||
}
|
||||
}
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('entityId', entityId)
|
||||
.input('firstName', firstName)
|
||||
.input('name', name)
|
||||
.input('street', street)
|
||||
.input('streetNumber', streetNumber)
|
||||
.input('zip', zip)
|
||||
.input('city', city)
|
||||
.input('county', county)
|
||||
.input('addressType', addressType)
|
||||
.query(UPDATE);
|
||||
|
||||
const row = result.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Address not found');
|
||||
}
|
||||
return shape(row);
|
||||
};
|
||||
}
|
||||
39
src/store/entitycontact/create.js
Normal file
39
src/store/entitycontact/create.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import { CREATE } from '../../sql/entitycontact.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
entityId: row.entityId,
|
||||
contactType: row.contactType,
|
||||
contact: row.contact,
|
||||
};
|
||||
}
|
||||
|
||||
export default function create(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId, input = {}) => {
|
||||
const contactType = input.contactType?.trim?.()
|
||||
? input.contactType.trim()
|
||||
: null;
|
||||
const contact = input.contact?.trim?.() ? input.contact.trim() : null;
|
||||
if (!contactType || !contact) {
|
||||
throw new Error('Contact required');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('entityId', entityId)
|
||||
.input('contactType', contactType)
|
||||
.input('contact', contact)
|
||||
.query(CREATE);
|
||||
|
||||
return shape(result.recordset[0]);
|
||||
};
|
||||
}
|
||||
27
src/store/entitycontact/delete.js
Normal file
27
src/store/entitycontact/delete.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { DELETE_BY_ENTITY_AND_ID } from '../../sql/entitycontact.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
export default function del(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId, id) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Contact not found');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('entityId', entityId)
|
||||
.query(DELETE_BY_ENTITY_AND_ID);
|
||||
|
||||
if (!result.rowsAffected[0]) {
|
||||
throw new Error('Contact not found');
|
||||
}
|
||||
};
|
||||
}
|
||||
29
src/store/entitycontact/list.js
Normal file
29
src/store/entitycontact/list.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { LIST_BY_ENTITY } from '../../sql/entitycontact.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
entityId: row.entityId,
|
||||
contactType: row.contactType,
|
||||
contact: row.contact,
|
||||
};
|
||||
}
|
||||
|
||||
export default function list(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId) => {
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('entityId', entityId)
|
||||
.query(LIST_BY_ENTITY);
|
||||
|
||||
return result.recordset.map(shape);
|
||||
};
|
||||
}
|
||||
67
src/store/entitycontact/update.js
Normal file
67
src/store/entitycontact/update.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import { GET_BY_ENTITY_AND_ID, UPDATE } from '../../sql/entitycontact.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
entityId: row.entityId,
|
||||
contactType: row.contactType,
|
||||
contact: row.contact,
|
||||
};
|
||||
}
|
||||
|
||||
export default function update(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
const entityAccess = resolveEntityAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, entityId, id, patch = {}) => {
|
||||
if (!Number.isFinite(id)) {
|
||||
throw new Error('Contact not found');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
await entityAccess(companyId, entityId);
|
||||
|
||||
const existing = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('entityId', entityId)
|
||||
.query(GET_BY_ENTITY_AND_ID);
|
||||
|
||||
const current = existing.recordset[0];
|
||||
if (!current) {
|
||||
throw new Error('Contact not found');
|
||||
}
|
||||
|
||||
let contactType = current.contactType;
|
||||
if (Object.prototype.hasOwnProperty.call(patch, 'contactType')) {
|
||||
contactType = patch.contactType?.trim?.()
|
||||
? patch.contactType.trim()
|
||||
: null;
|
||||
}
|
||||
|
||||
let contact = current.contact;
|
||||
if (Object.prototype.hasOwnProperty.call(patch, 'contact')) {
|
||||
contact = patch.contact?.trim?.() ? patch.contact.trim() : null;
|
||||
}
|
||||
|
||||
if (!contactType || !contact) {
|
||||
throw new Error('Contact required');
|
||||
}
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('entityId', entityId)
|
||||
.input('contactType', contactType)
|
||||
.input('contact', contact)
|
||||
.query(UPDATE);
|
||||
|
||||
const row = result.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Contact not found');
|
||||
}
|
||||
return shape(row);
|
||||
};
|
||||
}
|
||||
@@ -23,6 +23,7 @@ export default function create(pool) {
|
||||
|
||||
const created = await request(pool, tx)
|
||||
.input('customergroupId', customergroupId)
|
||||
.input('firstName', null)
|
||||
.input('name', cleaned)
|
||||
.query(CREATE);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user