Add customergroup sort with bulk order and locked implicit names.
Reorder via customergroup.order (exact id list → sort 0…n-1); block renaming POS/Lieferanten while still allowing create/update of other groups by name.
This commit is contained in:
12
README.md
12
README.md
@@ -193,12 +193,15 @@ 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 }` |
|
||||
| `list` | `(googleAuthId, companyId)` | `{ id, name, sort }[]` |
|
||||
| `create` | `(googleAuthId, companyId, { name })` | `{ id, name, sort }` |
|
||||
| `update` | `(googleAuthId, companyId, id, { name })` | `{ id, name, sort }` |
|
||||
| `order` | `(googleAuthId, companyId, { customergroupIds })` | `{ customergroupIds }` |
|
||||
| `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`.
|
||||
List ordered by `sort`, `name`, `id`. `create` appends with next `sort` (`0…n`). `order` sets `sort` to each id’s index `0…n-1`; `customergroupIds` must be exactly the company’s groups (same set, no dups) else `Invalid customer group order`. Implicit groups `POS` (company create) and `Lieferanten` (first supplier) cannot be renamed (`Name cannot be changed`). Creating a group with those reserved names → `Name not allowed`.
|
||||
|
||||
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`, `Name not allowed`, `Name cannot be changed`, `Invalid customer group order`, `Customer group not found`, `Customer group in use`.
|
||||
|
||||
---
|
||||
|
||||
@@ -682,6 +685,7 @@ res.set('Content-Type', thumb.contentType).send(thumb.buffer);
|
||||
| `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 })` |
|
||||
| `PUT /api/customergroup/order` | `customergroup.order(googleAuthId, companyId, { customergroupIds })` |
|
||||
| `DELETE /api/customergroup/:id` | `customergroup.delete(googleAuthId, companyId, id)` |
|
||||
| `GET /api/entity` | `entity.list(googleAuthId, companyId, { customergroupId?, role? })` |
|
||||
| `GET /api/entity/:id` | `entity.getById(googleAuthId, companyId, id)` |
|
||||
|
||||
@@ -9,7 +9,7 @@ digraph schema {
|
||||
label="Identity & Company"; labeljust="l"; fontsize=15;
|
||||
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>>];
|
||||
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><TR><TD PORT="sort" 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">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</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>>];
|
||||
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>>];
|
||||
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><TR><TD PORT="sort" 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">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
|
||||
@@ -42,27 +42,31 @@
|
||||
<!-- customergroup -->
|
||||
<g id="node1" class="node">
|
||||
<title>customergroup</title>
|
||||
<polygon fill="#bee3f8" stroke="none" points="527.76,-644.8 527.76,-673.2 664.24,-673.2 664.24,-644.8 527.76,-644.8"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-644.8 527.76,-673.2 664.24,-673.2 664.24,-644.8 527.76,-644.8"/>
|
||||
<polygon fill="#bee3f8" stroke="none" points="529.76,-667.2 529.76,-671.2 573.92,-671.2 573.92,-667.2 529.76,-667.2"/>
|
||||
<polygon fill="#bee3f8" stroke="none" points="573.92,-667.2 573.92,-671.2 618.08,-671.2 618.08,-667.2 573.92,-667.2"/>
|
||||
<polygon fill="#bee3f8" stroke="none" points="618.08,-667.2 618.08,-671.2 662.24,-671.2 662.24,-667.2 618.08,-667.2"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="552" y="-654.4" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#1a365d">customergroup</text>
|
||||
<polygon fill="#ebf8ff" stroke="none" points="527.76,-618 527.76,-644.8 664.24,-644.8 664.24,-618 527.76,-618"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-618 527.76,-644.8 664.24,-644.8 664.24,-618 527.76,-618"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="532.76" y="-628.2" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="629.73" y="-629.7" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="646.73" y="-629.7" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">PK</text>
|
||||
<polygon fill="#ebf8ff" stroke="none" points="527.76,-591.2 527.76,-618 664.24,-618 664.24,-591.2 527.76,-591.2"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-591.2 527.76,-618 664.24,-618 664.24,-591.2 527.76,-591.2"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="532.76" y="-601.4" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">company_id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="614.45" y="-601.4" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">?</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="630.24" y="-602.9" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="647.24" y="-602.9" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text>
|
||||
<polygon fill="#ffffff" stroke="none" points="527.76,-564.4 527.76,-591.2 664.24,-591.2 664.24,-564.4 527.76,-564.4"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-564.4 527.76,-591.2 664.24,-591.2 664.24,-564.4 527.76,-564.4"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="532.76" y="-572.2" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">name</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="587.72" y="-574.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">NVARCHAR(255)</text>
|
||||
<polygon fill="#bee3f8" stroke="none" points="527.76,-658.2 527.76,-686.6 664.24,-686.6 664.24,-658.2 527.76,-658.2"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-658.2 527.76,-686.6 664.24,-686.6 664.24,-658.2 527.76,-658.2"/>
|
||||
<polygon fill="#bee3f8" stroke="none" points="529.76,-680.6 529.76,-684.6 573.92,-684.6 573.92,-680.6 529.76,-680.6"/>
|
||||
<polygon fill="#bee3f8" stroke="none" points="573.92,-680.6 573.92,-684.6 618.08,-684.6 618.08,-680.6 573.92,-680.6"/>
|
||||
<polygon fill="#bee3f8" stroke="none" points="618.08,-680.6 618.08,-684.6 662.24,-684.6 662.24,-680.6 618.08,-680.6"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="552" y="-667.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#1a365d">customergroup</text>
|
||||
<polygon fill="#ebf8ff" stroke="none" points="527.76,-631.4 527.76,-658.2 664.24,-658.2 664.24,-631.4 527.76,-631.4"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-631.4 527.76,-658.2 664.24,-658.2 664.24,-631.4 527.76,-631.4"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="532.76" y="-641.6" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="629.73" y="-643.1" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="646.73" y="-643.1" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">PK</text>
|
||||
<polygon fill="#ebf8ff" stroke="none" points="527.76,-604.6 527.76,-631.4 664.24,-631.4 664.24,-604.6 527.76,-604.6"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-604.6 527.76,-631.4 664.24,-631.4 664.24,-604.6 527.76,-604.6"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="532.76" y="-614.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">company_id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="614.45" y="-614.8" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">?</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="630.24" y="-616.3" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="647.24" y="-616.3" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text>
|
||||
<polygon fill="#ffffff" stroke="none" points="527.76,-577.8 527.76,-604.6 664.24,-604.6 664.24,-577.8 527.76,-577.8"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-577.8 527.76,-604.6 664.24,-604.6 664.24,-577.8 527.76,-577.8"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="532.76" y="-585.6" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">name</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="587.72" y="-587.6" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">NVARCHAR(255)</text>
|
||||
<polygon fill="#f7fafc" stroke="none" points="527.76,-551 527.76,-577.8 664.24,-577.8 664.24,-551 527.76,-551"/>
|
||||
<polygon fill="none" stroke="#a0aec0" points="527.76,-551 527.76,-577.8 664.24,-577.8 664.24,-551 527.76,-551"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="532.76" y="-558.8" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">sort</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="644.74" y="-560.8" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT</text>
|
||||
</g>
|
||||
<!-- company -->
|
||||
<g id="node8" class="node">
|
||||
@@ -129,8 +133,8 @@
|
||||
<g id="edge8" class="edge">
|
||||
<title>customergroup:w->company:n</title>
|
||||
<g id="a_edge8"><a xlink:title="FK_customergroup_company">
|
||||
<path fill="none" stroke="#97266d" stroke-width="1.4" d="M526.76,-604.6C507.12,-604.6 515.85,-576.03 527.76,-560.4 578.18,-494.28 625.72,-524.34 707,-506.8 828.73,-480.53 1254.71,-553.72 1275.44,-438.79"/>
|
||||
<polygon fill="#97266d" stroke="#97266d" stroke-width="1.4" points="1277.87,-439.1 1276.04,-431.91 1272.99,-438.67 1277.87,-439.1"/>
|
||||
<path fill="none" stroke="#97266d" stroke-width="1.4" d="M526.76,-618C510.99,-618 517.82,-559.25 527.76,-547 579.23,-483.63 626.64,-521.22 707,-506.8 767,-496.03 1231.62,-493.81 1273.24,-438.03"/>
|
||||
<polygon fill="#97266d" stroke="#97266d" stroke-width="1.4" points="1275.42,-439.21 1275.5,-431.79 1270.82,-437.54 1275.42,-439.21"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
@@ -294,8 +298,8 @@
|
||||
<g id="edge10" class="edge">
|
||||
<title>entity:nw->customergroup:n</title>
|
||||
<g id="a_edge10"><a xlink:title="FK_entity_customergroup">
|
||||
<path fill="none" stroke="#276749" stroke-width="1.4" d="M718.05,-1034.6C718.05,-1034.6 617.38,-735.68 598.9,-680.8"/>
|
||||
<polygon fill="#276749" stroke="#276749" stroke-width="1.4" points="601.23,-680.06 596.68,-674.21 596.59,-681.62 601.23,-680.06"/>
|
||||
<path fill="none" stroke="#276749" stroke-width="1.4" d="M718.05,-1034.6C718.05,-1034.6 617.38,-746.73 598.9,-693.88"/>
|
||||
<polygon fill="#276749" stroke="#276749" stroke-width="1.4" points="601.32,-693.4 596.7,-687.6 596.7,-695.02 601.32,-693.4"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
@@ -422,8 +426,8 @@
|
||||
<g id="edge9" class="edge">
|
||||
<title>company:w->customergroup:n</title>
|
||||
<g id="a_edge9"><a xlink:title="FK_company_poscustomergroup">
|
||||
<path fill="none" stroke="#4c51bf" stroke-width="1.4" d="M1244.61,-281.8C985.59,-281.8 872.16,-307.27 707,-506.8 659.38,-564.33 729.51,-623.27 672.24,-671.2 664.54,-677.64 651.81,-682.57 644.93,-679.97"/>
|
||||
<polygon fill="#4c51bf" stroke="#4c51bf" stroke-width="1.4" points="647.02,-678.69 641.27,-674.01 642.84,-681.25 647.02,-678.69"/>
|
||||
<path fill="none" stroke="#4c51bf" stroke-width="1.4" d="M1244.61,-281.8C985.59,-281.8 870.62,-306.01 707,-506.8 656.14,-569.22 733.59,-632.46 672.24,-684.6 664.42,-691.24 651.27,-696.22 644.49,-693.2"/>
|
||||
<polygon fill="#4c51bf" stroke="#4c51bf" stroke-width="1.4" points="646.8,-692.31 641.21,-687.44 642.54,-694.74 646.8,-692.31"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
@@ -1676,8 +1680,8 @@
|
||||
<g id="edge45" class="edge">
|
||||
<title>price:se->customergroup:n</title>
|
||||
<g id="a_edge45"><a xlink:title="FK_price_customergroup">
|
||||
<path fill="none" stroke="#dd6b20" stroke-width="1.4" d="M476.95,-1413C489.04,-1400.91 487.42,-1276.62 489,-1259.6 512.98,-1001.1 550.98,-936.21 551.83,-680.97"/>
|
||||
<polygon fill="#dd6b20" stroke="#dd6b20" stroke-width="1.4" points="554.28,-681.32 551.84,-674.32 549.38,-681.31 554.28,-681.32"/>
|
||||
<path fill="none" stroke="#dd6b20" stroke-width="1.4" d="M476.95,-1413C489.04,-1400.91 487.4,-1276.62 489,-1259.6 512.74,-1007.09 550.94,-943.71 551.83,-694.54"/>
|
||||
<polygon fill="#dd6b20" stroke="#dd6b20" stroke-width="1.4" points="554.28,-694.72 551.84,-687.72 549.38,-694.71 554.28,-694.72"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
@@ -164,6 +164,7 @@ const MENU = {
|
||||
{ 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.order', label: 'order', hint: 'googleAuthId, companyId, JSON customergroupIds → { customergroupIds }' },
|
||||
{ value: 'customergroup.delete', label: 'delete', hint: 'googleAuthId, companyId, id' },
|
||||
],
|
||||
},
|
||||
@@ -799,9 +800,11 @@ async function runMethod(client, action) {
|
||||
if (name == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.customergroup.create(Number(googleAuthId), Number(companyId), {
|
||||
name,
|
||||
}),
|
||||
await client.customergroup.create(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
{ name },
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'customergroup.update': {
|
||||
@@ -825,6 +828,33 @@ async function runMethod(client, action) {
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'customergroup.order': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
const companyId = await askInt('company id');
|
||||
if (companyId == null) return;
|
||||
const idsJson = await askText('customergroupIds JSON', {
|
||||
placeholder: '[3,1,2]',
|
||||
validate: (v) => {
|
||||
if (!v?.trim()) return 'Required';
|
||||
try {
|
||||
const parsed = JSON.parse(v);
|
||||
if (!Array.isArray(parsed)) return 'Must be a JSON array';
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
},
|
||||
});
|
||||
if (idsJson == null) return;
|
||||
return [
|
||||
'result',
|
||||
await client.customergroup.order(
|
||||
Number(googleAuthId),
|
||||
Number(companyId),
|
||||
{ customergroupIds: JSON.parse(idsJson) },
|
||||
),
|
||||
];
|
||||
}
|
||||
case 'customergroup.delete': {
|
||||
const googleAuthId = await askInt('google_auth id');
|
||||
if (googleAuthId == null) return;
|
||||
|
||||
@@ -42,6 +42,7 @@ 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 customergroupOrder from './store/customergroup/order.js';
|
||||
import customergroupDelete from './store/customergroup/delete.js';
|
||||
import entityList from './store/entity/list.js';
|
||||
import entityGetById from './store/entity/getById.js';
|
||||
@@ -181,6 +182,7 @@ export default class LibDashStore {
|
||||
list: customergroupList(pool),
|
||||
create: customergroupCreate(pool),
|
||||
update: customergroupUpdate(pool),
|
||||
order: customergroupOrder(pool),
|
||||
delete: customergroupDelete(pool),
|
||||
};
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ BEGIN
|
||||
CREATE TABLE customergroup (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
name NVARCHAR(255) NOT NULL,
|
||||
sort INT NOT NULL CONSTRAINT DF_customergroup_sort DEFAULT 0,
|
||||
-- Nullable only for company-create chicken-egg (POS group first, then company, then SET).
|
||||
-- Always set before commit; never left null for live rows.
|
||||
company_id INT NULL,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
export const CREATE = `
|
||||
INSERT INTO customergroup (name, company_id)
|
||||
OUTPUT INSERTED.id, INSERTED.name
|
||||
VALUES (@name, @companyId)
|
||||
INSERT INTO customergroup (name, company_id, sort)
|
||||
OUTPUT INSERTED.id, INSERTED.name, INSERTED.sort
|
||||
VALUES (@name, @companyId, @sort)
|
||||
`;
|
||||
|
||||
export const CREATE_WITHOUT_COMPANY = `
|
||||
INSERT INTO customergroup (name)
|
||||
OUTPUT INSERTED.id
|
||||
VALUES (@name)
|
||||
INSERT INTO customergroup (name, sort)
|
||||
OUTPUT INSERTED.id, INSERTED.name, INSERTED.sort
|
||||
VALUES (@name, @sort)
|
||||
`;
|
||||
|
||||
export const SET_COMPANY = `
|
||||
@@ -17,28 +17,46 @@ WHERE id = @id
|
||||
`;
|
||||
|
||||
export const GET_BY_COMPANY_AND_NAME = `
|
||||
SELECT id, name
|
||||
SELECT id, name, sort
|
||||
FROM customergroup
|
||||
WHERE company_id = @companyId AND name = @name
|
||||
`;
|
||||
|
||||
export const LIST_BY_COMPANY = `
|
||||
SELECT id, name
|
||||
SELECT id, name, sort
|
||||
FROM customergroup
|
||||
WHERE company_id = @companyId
|
||||
ORDER BY name, id
|
||||
ORDER BY sort ASC, name ASC, id ASC
|
||||
`;
|
||||
|
||||
export const GET_BY_COMPANY_AND_ID = `
|
||||
SELECT id, name
|
||||
SELECT id, name, sort
|
||||
FROM customergroup
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
export const UPDATE_NAME = `
|
||||
export const GET_NEXT_SORT = `
|
||||
SELECT ISNULL(MAX(sort), -1) + 1 AS sort
|
||||
FROM customergroup
|
||||
WHERE company_id = @companyId
|
||||
`;
|
||||
|
||||
export const LIST_IDS_BY_COMPANY = `
|
||||
SELECT id
|
||||
FROM customergroup
|
||||
WHERE company_id = @companyId
|
||||
`;
|
||||
|
||||
export const UPDATE = `
|
||||
UPDATE customergroup
|
||||
SET name = @name
|
||||
OUTPUT INSERTED.id, INSERTED.name
|
||||
OUTPUT INSERTED.id, INSERTED.name, INSERTED.sort
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
export const UPDATE_SORT = `
|
||||
UPDATE customergroup
|
||||
SET sort = @sort
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { POS_GROUP_NAME } from '../../sql/entity.js';
|
||||
import { CREATE } from '../../sql/company.js';
|
||||
import { CREATE as CREATE_CATEGORY } from '../../sql/category.js';
|
||||
import {
|
||||
@@ -10,8 +11,6 @@ import langEnsure from '../lang/ensure.js';
|
||||
import taxEnsure from '../tax/ensure.js';
|
||||
import request from '../request.js';
|
||||
|
||||
const POS_CUSTOMERGROUP_NAME = 'POS';
|
||||
|
||||
export default function create(pool) {
|
||||
const nameTaken = getByName(pool);
|
||||
const ensureLang = langEnsure(pool);
|
||||
@@ -42,7 +41,8 @@ export default function create(pool) {
|
||||
// Circular FK: create POS group first (company_id null), company with
|
||||
// poscustomergroup_id NOT NULL, then link the group back to the company.
|
||||
const posGroup = await request(pool, tx)
|
||||
.input('name', POS_CUSTOMERGROUP_NAME)
|
||||
.input('name', POS_GROUP_NAME)
|
||||
.input('sort', 0)
|
||||
.query(CREATE_CUSTOMERGROUP);
|
||||
|
||||
const posCustomerGroupId = posGroup.recordset[0].id;
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { CREATE } from '../../sql/customergroup.js';
|
||||
import { CREATE, GET_NEXT_SORT } from '../../sql/customergroup.js';
|
||||
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
const RESERVED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
|
||||
|
||||
function shape(row) {
|
||||
return { id: row.id, name: row.name, sort: row.sort };
|
||||
}
|
||||
|
||||
export default function create(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
@@ -9,16 +16,25 @@ export default function create(pool) {
|
||||
if (!cleaned) {
|
||||
throw new Error('Name required');
|
||||
}
|
||||
if (RESERVED_NAMES.has(cleaned)) {
|
||||
throw new Error('Name not allowed');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
const next = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.query(GET_NEXT_SORT);
|
||||
const sort = next.recordset[0].sort;
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.input('name', cleaned)
|
||||
.input('sort', sort)
|
||||
.query(CREATE);
|
||||
|
||||
const row = result.recordset[0];
|
||||
return { id: row.id, name: row.name };
|
||||
return shape(result.recordset[0]);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ export default function list(pool) {
|
||||
return result.recordset.map((row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
sort: row.sort,
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
65
src/store/customergroup/order.js
Normal file
65
src/store/customergroup/order.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
LIST_IDS_BY_COMPANY,
|
||||
UPDATE_SORT,
|
||||
} from '../../sql/customergroup.js';
|
||||
import request from '../request.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
export default function order(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
return async (googleAuthId, companyId, { customergroupIds } = {}) => {
|
||||
if (!Array.isArray(customergroupIds)) {
|
||||
throw new Error('Invalid customer group order');
|
||||
}
|
||||
|
||||
await access(googleAuthId, companyId);
|
||||
|
||||
const groups = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.query(LIST_IDS_BY_COMPANY);
|
||||
|
||||
const existing = new Set(groups.recordset.map((r) => r.id));
|
||||
|
||||
if (customergroupIds.length !== existing.size) {
|
||||
throw new Error('Invalid customer group order');
|
||||
}
|
||||
|
||||
const seen = new Set();
|
||||
for (const customergroupId of customergroupIds) {
|
||||
if (
|
||||
!Number.isFinite(customergroupId) ||
|
||||
!existing.has(customergroupId) ||
|
||||
seen.has(customergroupId)
|
||||
) {
|
||||
throw new Error('Invalid customer group order');
|
||||
}
|
||||
seen.add(customergroupId);
|
||||
}
|
||||
|
||||
const tx = pool.transaction();
|
||||
await tx.begin();
|
||||
|
||||
try {
|
||||
for (let sort = 0; sort < customergroupIds.length; sort++) {
|
||||
await request(pool, tx)
|
||||
.input('id', customergroupIds[sort])
|
||||
.input('companyId', companyId)
|
||||
.input('sort', sort)
|
||||
.query(UPDATE_SORT);
|
||||
}
|
||||
|
||||
await tx.commit();
|
||||
|
||||
return { customergroupIds };
|
||||
} catch (err) {
|
||||
try {
|
||||
await tx.rollback();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
import { UPDATE_NAME } from '../../sql/customergroup.js';
|
||||
import { GET_BY_COMPANY_AND_ID, UPDATE } from '../../sql/customergroup.js';
|
||||
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||
|
||||
const LOCKED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
|
||||
|
||||
function shape(row) {
|
||||
return { id: row.id, name: row.name, sort: row.sort };
|
||||
}
|
||||
|
||||
export default function update(pool) {
|
||||
const access = resolveCompanyAccess(pool);
|
||||
|
||||
@@ -9,24 +16,39 @@ export default function update(pool) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
|
||||
const cleaned = name?.trim();
|
||||
const cleaned = name?.trim?.() ? name.trim() : null;
|
||||
if (!cleaned) {
|
||||
throw new Error('Name required');
|
||||
}
|
||||
|
||||
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('Customer group not found');
|
||||
}
|
||||
|
||||
if (LOCKED_NAMES.has(current.name) && cleaned !== current.name) {
|
||||
throw new Error('Name cannot be changed');
|
||||
}
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('id', id)
|
||||
.input('companyId', companyId)
|
||||
.input('name', cleaned)
|
||||
.query(UPDATE_NAME);
|
||||
.query(UPDATE);
|
||||
|
||||
const row = result.recordset[0];
|
||||
if (!row) {
|
||||
throw new Error('Customer group not found');
|
||||
}
|
||||
return { id: row.id, name: row.name };
|
||||
return shape(row);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
CREATE,
|
||||
GET_BY_COMPANY_AND_NAME,
|
||||
GET_NEXT_SORT,
|
||||
} from '../../sql/customergroup.js';
|
||||
import { SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
||||
|
||||
@@ -17,9 +18,15 @@ export default async function ensureLieferantenGroup(pool, companyId, tx) {
|
||||
return existing.recordset[0].id;
|
||||
}
|
||||
|
||||
const next = await req()
|
||||
.input('companyId', companyId)
|
||||
.query(GET_NEXT_SORT);
|
||||
const sort = next.recordset[0].sort;
|
||||
|
||||
const created = await req()
|
||||
.input('companyId', companyId)
|
||||
.input('name', SUPPLIER_GROUP_NAME)
|
||||
.input('sort', sort)
|
||||
.query(CREATE);
|
||||
|
||||
return created.recordset[0].id;
|
||||
|
||||
Reference in New Issue
Block a user