feat: add invoice-config-items management functionality

This commit is contained in:
Tran Anh Tuan
2026-05-12 09:52:25 +07:00
parent eac8a686d1
commit c39b010e5e
14 changed files with 1571 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ const (
API_GROUP_COMPONENT_CODE = "/component-codes"
API_GROUP_COMPONENT_ITEM = "/component-items"
API_GROUP_INVOICE_CONFIG = "/invoice-configs"
API_GROUP_INVOICE_CONFIG_ITEM = "/invoice-config-items"
)
const (

View File

@@ -0,0 +1,33 @@
-- name: GetInvoiceConfigItemByID :one
SELECT * FROM invoice_config_items
WHERE id = sqlc.arg(id);
-- name: ListInvoiceConfigItems :many
SELECT * FROM invoice_config_items;
-- name: CreateInvoiceConfigItem :one
INSERT INTO invoice_config_items (invoice_config_id,component_id,required_quantity, allow_alternative,priority_order, note, metadata)
VALUES (
sqlc.arg(invoice_config_id),
sqlc.arg(component_id),
sqlc.arg(required_quantity),
sqlc.arg(allow_alternative),
sqlc.arg(priority_order),
sqlc.arg(note),
sqlc.arg(metadata)
)
RETURNING *;
-- name: UpdateInvoiceConfigItem :one
UPDATE invoice_config_items
SET required_quantity = coalesce(sqlc.arg(required_quantity), required_quantity),
allow_alternative = coalesce(sqlc.arg(allow_alternative), allow_alternative),
priority_order = coalesce(sqlc.arg(priority_order), priority_order),
note = coalesce(sqlc.arg(note), note),
metadata = coalesce(sqlc.arg(metadata), metadata)
WHERE id = sqlc.arg(id)
RETURNING *;
-- name: DeleteInvoiceConfigItem :execrows
DELETE FROM invoice_config_items
WHERE id = sqlc.arg(id);

View File

@@ -1873,6 +1873,279 @@ const docTemplate = `{
}
}
},
"/v1/invoice-config-items": {
"get": {
"description": "Retrieve a list of all invoice config items",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "List all invoice config items",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/models.InvoiceConfigItem"
}
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"post": {
"description": "Create a new invoice config item with the provided details",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Create a new invoice config item",
"parameters": [
{
"description": "Invoice config item request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.CreateInvoiceConfigItemRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.CreateInvoiceConfigItemResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/v1/invoice-config-items/{id}": {
"get": {
"description": "Retrieve a single invoice config item using its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Get invoice config item by ID",
"parameters": [
{
"type": "integer",
"description": "Invoice config item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.InvoiceConfigItem"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"put": {
"description": "Update an existing invoice config item by its ID. Only non-empty fields will be updated.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Update invoice config item",
"parameters": [
{
"type": "integer",
"description": "Invoice config item ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Invoice config item request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.UpdateInvoiceConfigItemRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.UpdateInvoiceConfigItemResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"delete": {
"description": "Delete an invoice config item by its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Delete invoice config item",
"parameters": [
{
"type": "integer",
"description": "Invoice config item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.SuccessResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/v1/invoice-configs": {
"get": {
"description": "Retrieve a list of all invoice configs ordered by creation date",
@@ -3211,6 +3484,38 @@ const docTemplate = `{
}
}
},
"models.InvoiceConfigItem": {
"type": "object",
"properties": {
"allowAlternative": {
"type": "boolean"
},
"componentId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"invoiceConfigId": {
"type": "integer"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"models.Room": {
"type": "object",
"properties": {
@@ -3463,6 +3768,35 @@ const docTemplate = `{
}
}
},
"requests.CreateInvoiceConfigItemRequest": {
"type": "object",
"required": [
"componentId",
"invoiceConfigId",
"priorityOrder",
"requiredQuantity"
],
"properties": {
"allowAlternative": {
"type": "boolean"
},
"componentId": {
"type": "integer"
},
"invoiceConfigId": {
"type": "integer"
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"requests.CreateInvoiceConfigRequest": {
"type": "object",
"required": [
@@ -3683,6 +4017,23 @@ const docTemplate = `{
}
}
},
"requests.UpdateInvoiceConfigItemRequest": {
"type": "object",
"properties": {
"allowAlternative": {
"type": "boolean"
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"requests.UpdateInvoiceConfigRequest": {
"type": "object",
"properties": {
@@ -3828,6 +4179,14 @@ const docTemplate = `{
}
}
},
"responses.CreateInvoiceConfigItemResponse": {
"type": "object",
"properties": {
"id": {
"type": "integer"
}
}
},
"responses.CreateInvoiceConfigResponse": {
"type": "object",
"properties": {
@@ -4015,6 +4374,32 @@ const docTemplate = `{
}
}
},
"responses.UpdateInvoiceConfigItemResponse": {
"type": "object",
"properties": {
"allowAlternative": {
"type": "boolean"
},
"componentId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"invoiceConfigId": {
"type": "integer"
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"responses.UpdateInvoiceConfigResponse": {
"type": "object",
"properties": {

View File

@@ -1867,6 +1867,279 @@
}
}
},
"/v1/invoice-config-items": {
"get": {
"description": "Retrieve a list of all invoice config items",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "List all invoice config items",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/models.InvoiceConfigItem"
}
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"post": {
"description": "Create a new invoice config item with the provided details",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Create a new invoice config item",
"parameters": [
{
"description": "Invoice config item request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.CreateInvoiceConfigItemRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.CreateInvoiceConfigItemResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/v1/invoice-config-items/{id}": {
"get": {
"description": "Retrieve a single invoice config item using its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Get invoice config item by ID",
"parameters": [
{
"type": "integer",
"description": "Invoice config item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.InvoiceConfigItem"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"put": {
"description": "Update an existing invoice config item by its ID. Only non-empty fields will be updated.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Update invoice config item",
"parameters": [
{
"type": "integer",
"description": "Invoice config item ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Invoice config item request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.UpdateInvoiceConfigItemRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.UpdateInvoiceConfigItemResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"delete": {
"description": "Delete an invoice config item by its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"invoice-config-item"
],
"summary": "Delete invoice config item",
"parameters": [
{
"type": "integer",
"description": "Invoice config item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.SuccessResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/v1/invoice-configs": {
"get": {
"description": "Retrieve a list of all invoice configs ordered by creation date",
@@ -3205,6 +3478,38 @@
}
}
},
"models.InvoiceConfigItem": {
"type": "object",
"properties": {
"allowAlternative": {
"type": "boolean"
},
"componentId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"invoiceConfigId": {
"type": "integer"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"models.Room": {
"type": "object",
"properties": {
@@ -3457,6 +3762,35 @@
}
}
},
"requests.CreateInvoiceConfigItemRequest": {
"type": "object",
"required": [
"componentId",
"invoiceConfigId",
"priorityOrder",
"requiredQuantity"
],
"properties": {
"allowAlternative": {
"type": "boolean"
},
"componentId": {
"type": "integer"
},
"invoiceConfigId": {
"type": "integer"
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"requests.CreateInvoiceConfigRequest": {
"type": "object",
"required": [
@@ -3677,6 +4011,23 @@
}
}
},
"requests.UpdateInvoiceConfigItemRequest": {
"type": "object",
"properties": {
"allowAlternative": {
"type": "boolean"
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"requests.UpdateInvoiceConfigRequest": {
"type": "object",
"properties": {
@@ -3822,6 +4173,14 @@
}
}
},
"responses.CreateInvoiceConfigItemResponse": {
"type": "object",
"properties": {
"id": {
"type": "integer"
}
}
},
"responses.CreateInvoiceConfigResponse": {
"type": "object",
"properties": {
@@ -4009,6 +4368,32 @@
}
}
},
"responses.UpdateInvoiceConfigItemResponse": {
"type": "object",
"properties": {
"allowAlternative": {
"type": "boolean"
},
"componentId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"invoiceConfigId": {
"type": "integer"
},
"note": {
"type": "string"
},
"priorityOrder": {
"type": "integer"
},
"requiredQuantity": {
"type": "integer"
}
}
},
"responses.UpdateInvoiceConfigResponse": {
"type": "object",
"properties": {

View File

@@ -164,6 +164,27 @@ definitions:
updatedAt:
type: string
type: object
models.InvoiceConfigItem:
properties:
allowAlternative:
type: boolean
componentId:
type: integer
id:
type: integer
invoiceConfigId:
type: integer
metadata:
items:
type: integer
type: array
note:
type: string
priorityOrder:
type: integer
requiredQuantity:
type: integer
type: object
models.Room:
properties:
createdAt:
@@ -333,6 +354,26 @@ definitions:
- name
- shelfId
type: object
requests.CreateInvoiceConfigItemRequest:
properties:
allowAlternative:
type: boolean
componentId:
type: integer
invoiceConfigId:
type: integer
note:
type: string
priorityOrder:
type: integer
requiredQuantity:
type: integer
required:
- componentId
- invoiceConfigId
- priorityOrder
- requiredQuantity
type: object
requests.CreateInvoiceConfigRequest:
properties:
description:
@@ -479,6 +520,17 @@ definitions:
name:
type: string
type: object
requests.UpdateInvoiceConfigItemRequest:
properties:
allowAlternative:
type: boolean
note:
type: string
priorityOrder:
type: integer
requiredQuantity:
type: integer
type: object
requests.UpdateInvoiceConfigRequest:
properties:
description:
@@ -572,6 +624,11 @@ definitions:
id:
type: integer
type: object
responses.CreateInvoiceConfigItemResponse:
properties:
id:
type: integer
type: object
responses.CreateInvoiceConfigResponse:
properties:
id:
@@ -693,6 +750,23 @@ definitions:
shelfId:
type: integer
type: object
responses.UpdateInvoiceConfigItemResponse:
properties:
allowAlternative:
type: boolean
componentId:
type: integer
id:
type: integer
invoiceConfigId:
type: integer
note:
type: string
priorityOrder:
type: integer
requiredQuantity:
type: integer
type: object
responses.UpdateInvoiceConfigResponse:
properties:
description:
@@ -1908,6 +1982,176 @@ paths:
summary: Update container
tags:
- container
/v1/invoice-config-items:
get:
consumes:
- application/json
description: Retrieve a list of all invoice config items
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
items:
$ref: '#/definitions/models.InvoiceConfigItem'
type: array
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: List all invoice config items
tags:
- invoice-config-item
post:
consumes:
- application/json
description: Create a new invoice config item with the provided details
parameters:
- description: Invoice config item request body
in: body
name: body
required: true
schema:
$ref: '#/definitions/requests.CreateInvoiceConfigItemRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
$ref: '#/definitions/responses.CreateInvoiceConfigItemResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Create a new invoice config item
tags:
- invoice-config-item
/v1/invoice-config-items/{id}:
delete:
consumes:
- application/json
description: Delete an invoice config item by its unique identifier
parameters:
- description: Invoice config item ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.SuccessResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Delete invoice config item
tags:
- invoice-config-item
get:
consumes:
- application/json
description: Retrieve a single invoice config item using its unique identifier
parameters:
- description: Invoice config item ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
$ref: '#/definitions/models.InvoiceConfigItem'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Get invoice config item by ID
tags:
- invoice-config-item
put:
consumes:
- application/json
description: Update an existing invoice config item by its ID. Only non-empty
fields will be updated.
parameters:
- description: Invoice config item ID
in: path
name: id
required: true
type: integer
- description: Invoice config item request body
in: body
name: body
required: true
schema:
$ref: '#/definitions/requests.UpdateInvoiceConfigItemRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
$ref: '#/definitions/responses.UpdateInvoiceConfigItemResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Update invoice config item
tags:
- invoice-config-item
/v1/invoice-configs:
get:
consumes:

View File

@@ -0,0 +1,50 @@
package mapper
import (
"wm-backend/internal/models"
db "wm-backend/sqlc_gen"
"github.com/jackc/pgx/v5/pgtype"
)
func ToDomainInvoiceConfigItem(r db.InvoiceConfigItem) *models.InvoiceConfigItem {
return &models.InvoiceConfigItem{
ID: r.ID,
InvoiceConfigID: r.InvoiceConfigID,
ComponentID: r.ComponentID,
RequiredQuantity: r.RequiredQuantity,
AllowAlternative: r.AllowAlternative,
PriorityOrder: r.PriorityOrder,
Note: r.Note.String,
Metadata: r.Metadata,
}
}
func ToModelInvoiceConfigItem(r *models.InvoiceConfigItem) *db.CreateInvoiceConfigItemParams {
return &db.CreateInvoiceConfigItemParams{
InvoiceConfigID: r.InvoiceConfigID,
ComponentID: r.ComponentID,
RequiredQuantity: r.RequiredQuantity,
AllowAlternative: r.AllowAlternative,
PriorityOrder: r.PriorityOrder,
Note: pgtype.Text{
String: r.Note,
Valid: r.Note != "",
},
Metadata: r.Metadata,
}
}
func ToUpdateModelInvoiceConfigItem(r *models.InvoiceConfigItem) *db.UpdateInvoiceConfigItemParams {
return &db.UpdateInvoiceConfigItemParams{
RequiredQuantity: r.RequiredQuantity,
AllowAlternative: r.AllowAlternative,
PriorityOrder: r.PriorityOrder,
Note: pgtype.Text{
String: r.Note,
Valid: r.Note != "",
},
Metadata: r.Metadata,
ID: r.ID,
}
}

View File

@@ -0,0 +1,12 @@
package models
type InvoiceConfigItem struct {
ID int64 `json:"id"`
InvoiceConfigID int64 `json:"invoiceConfigId"`
ComponentID int64 `json:"componentId"`
RequiredQuantity int32 `json:"requiredQuantity"`
AllowAlternative bool `json:"allowAlternative"`
PriorityOrder int32 `json:"priorityOrder"`
Note string `json:"note"`
Metadata []byte `json:"metadata"`
}

View File

@@ -0,0 +1,17 @@
package requests
type CreateInvoiceConfigItemRequest struct {
InvoiceConfigID int64 `json:"invoiceConfigId" binding:"required"`
ComponentID int64 `json:"componentId" binding:"required"`
RequiredQuantity int32 `json:"requiredQuantity" binding:"required"`
AllowAlternative bool `json:"allowAlternative"`
PriorityOrder int32 `json:"priorityOrder" binding:"required"`
Note string `json:"note"`
}
type UpdateInvoiceConfigItemRequest struct {
RequiredQuantity *int32 `json:"requiredQuantity"`
AllowAlternative *bool `json:"allowAlternative"`
PriorityOrder *int32 `json:"priorityOrder"`
Note string `json:"note"`
}

View File

@@ -0,0 +1,15 @@
package responses
type CreateInvoiceConfigItemResponse struct {
ID int64 `json:"id"`
}
type UpdateInvoiceConfigItemResponse struct {
ID int64 `json:"id"`
InvoiceConfigID int64 `json:"invoiceConfigId"`
ComponentID int64 `json:"componentId"`
RequiredQuantity int32 `json:"requiredQuantity"`
AllowAlternative bool `json:"allowAlternative"`
PriorityOrder int32 `json:"priorityOrder"`
Note string `json:"note"`
}

View File

@@ -0,0 +1,52 @@
package repositories
import (
"context"
"wm-backend/internal/mapper"
"wm-backend/internal/models"
db "wm-backend/sqlc_gen"
)
func CreateInvoiceConfigItem(ctx context.Context, queries *db.Queries, body models.InvoiceConfigItem) (models.InvoiceConfigItem, error) {
result, err := queries.CreateInvoiceConfigItem(ctx, *mapper.ToModelInvoiceConfigItem(&body))
if err != nil {
return models.InvoiceConfigItem{}, err
}
return *mapper.ToDomainInvoiceConfigItem(result), nil
}
func GetInvoiceConfigItemByID(ctx context.Context, queries *db.Queries, id int64) (models.InvoiceConfigItem, error) {
result, err := queries.GetInvoiceConfigItemByID(ctx, id)
if err != nil {
return models.InvoiceConfigItem{}, err
}
return *mapper.ToDomainInvoiceConfigItem(result), nil
}
func ListInvoiceConfigItems(ctx context.Context, queries *db.Queries) ([]models.InvoiceConfigItem, error) {
results, err := queries.ListInvoiceConfigItems(ctx)
if err != nil {
return nil, err
}
var items []models.InvoiceConfigItem
for _, r := range results {
items = append(items, *mapper.ToDomainInvoiceConfigItem(r))
}
return items, nil
}
func UpdateInvoiceConfigItem(ctx context.Context, queries *db.Queries, body models.InvoiceConfigItem) (models.InvoiceConfigItem, error) {
result, err := queries.UpdateInvoiceConfigItem(ctx, *mapper.ToUpdateModelInvoiceConfigItem(&body))
if err != nil {
return models.InvoiceConfigItem{}, err
}
return *mapper.ToDomainInvoiceConfigItem(result), nil
}
func DeleteInvoiceConfigItem(ctx context.Context, queries *db.Queries, id int64) (int64, error) {
rowsAffected, err := queries.DeleteInvoiceConfigItem(ctx, id)
if err != nil {
return rowsAffected, err
}
return rowsAffected, nil
}

View File

@@ -120,6 +120,15 @@ func NewRouter() *gin.Engine {
invoiceConfig.PUT("/:id", utils.AsyncHandler(services.InvoiceConfigUpdate))
invoiceConfig.DELETE("/:id", utils.AsyncHandler(services.InvoiceConfigDelete))
}
invoiceConfigItem := v1.Group(constants.API_GROUP_INVOICE_CONFIG_ITEM)
{
invoiceConfigItem.GET("", utils.AsyncHandler(services.InvoiceConfigItemList))
invoiceConfigItem.GET("/:id", utils.AsyncHandler(services.InvoiceConfigItemGetByID))
invoiceConfigItem.POST("", utils.AsyncHandler(services.InvoiceConfigItemCreate))
invoiceConfigItem.PUT("/:id", utils.AsyncHandler(services.InvoiceConfigItemUpdate))
invoiceConfigItem.DELETE("/:id", utils.AsyncHandler(services.InvoiceConfigItemDelete))
}
}
r.GET(constants.API_PATH_PING, services.PingHandler)

View File

@@ -0,0 +1,193 @@
package services
import (
"net/http"
"strconv"
"wm-backend/global"
"wm-backend/internal/models"
"wm-backend/internal/models/requests"
"wm-backend/internal/models/responses"
"wm-backend/internal/repositories"
"wm-backend/pkg/helper"
"wm-backend/response"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
)
// InvoiceConfigItemCreate creates a new invoice config item.
//
// @Summary Create a new invoice config item
// @Description Create a new invoice config item with the provided details
// @Tags invoice-config-item
// @Accept json
// @Produce json
// @Param body body requests.CreateInvoiceConfigItemRequest true "Invoice config item request body"
// @Success 201 {object} response.SuccessResponse{data=responses.CreateInvoiceConfigItemResponse}
// @Failure 400 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /v1/invoice-config-items [post]
func InvoiceConfigItemCreate(c *gin.Context) error {
requestBody := requests.CreateInvoiceConfigItemRequest{}
if helper.IsShouldBindJSON(c, &requestBody) {
return nil
}
invoiceConfigItemModel := &models.InvoiceConfigItem{
InvoiceConfigID: requestBody.InvoiceConfigID,
ComponentID: requestBody.ComponentID,
RequiredQuantity: requestBody.RequiredQuantity,
AllowAlternative: requestBody.AllowAlternative,
PriorityOrder: requestBody.PriorityOrder,
Note: requestBody.Note,
}
invoiceConfigItem, err := repositories.CreateInvoiceConfigItem(c.Request.Context(), global.Queries, *invoiceConfigItemModel)
if err != nil {
log.Error().Err(err).Msg("Failed to create invoice config item")
response.InternalServerError(c, http.StatusInternalServerError, "Failed to create invoice config item")
return nil
}
response.Created(c, "Invoice config item created successfully", &responses.CreateInvoiceConfigItemResponse{
ID: invoiceConfigItem.ID,
})
return nil
}
// InvoiceConfigItemGetByID retrieves a single invoice config item by its ID.
//
// @Summary Get invoice config item by ID
// @Description Retrieve a single invoice config item using its unique identifier
// @Tags invoice-config-item
// @Accept json
// @Produce json
// @Param id path int true "Invoice config item ID"
// @Success 200 {object} response.SuccessResponse{data=models.InvoiceConfigItem}
// @Failure 400 {object} response.ErrorResponse
// @Failure 404 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /v1/invoice-config-items/{id} [get]
func InvoiceConfigItemGetByID(c *gin.Context) error {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequestError(c, http.StatusBadRequest, "Invalid ID")
return nil
}
invoiceConfigItem, err := repositories.GetInvoiceConfigItemByID(c.Request.Context(), global.Queries, id)
if err != nil {
log.Error().Err(err).Msgf("Failed to get invoice config item by ID: %d", id)
response.NotFoundError(c, http.StatusNotFound, "Invoice config item not found")
return nil
}
response.Ok(c, "Success", invoiceConfigItem)
return nil
}
// InvoiceConfigItemList retrieves all invoice config items.
//
// @Summary List all invoice config items
// @Description Retrieve a list of all invoice config items
// @Tags invoice-config-item
// @Accept json
// @Produce json
// @Success 200 {object} response.SuccessResponse{data=[]models.InvoiceConfigItem}
// @Failure 500 {object} response.ErrorResponse
// @Router /v1/invoice-config-items [get]
func InvoiceConfigItemList(c *gin.Context) error {
invoiceConfigItems, err := repositories.ListInvoiceConfigItems(c.Request.Context(), global.Queries)
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError, "Failed to list invoice config items")
return nil
}
response.Ok(c, "Success", invoiceConfigItems)
return nil
}
// InvoiceConfigItemUpdate updates an existing invoice config item by its ID.
//
// @Summary Update invoice config item
// @Description Update an existing invoice config item by its ID. Only non-empty fields will be updated.
// @Tags invoice-config-item
// @Accept json
// @Produce json
// @Param id path int true "Invoice config item ID"
// @Param body body requests.UpdateInvoiceConfigItemRequest true "Invoice config item request body"
// @Success 200 {object} response.SuccessResponse{data=responses.UpdateInvoiceConfigItemResponse}
// @Failure 400 {object} response.ErrorResponse
// @Failure 404 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /v1/invoice-config-items/{id} [put]
func InvoiceConfigItemUpdate(c *gin.Context) error {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequestError(c, http.StatusBadRequest, "Invalid ID")
return nil
}
requestBody := requests.UpdateInvoiceConfigItemRequest{}
if helper.IsShouldBindJSON(c, &requestBody) {
return nil
}
existing, err := repositories.GetInvoiceConfigItemByID(c.Request.Context(), global.Queries, id)
if err != nil {
response.NotFoundError(c, http.StatusNotFound, "Invoice config item not found")
return nil
}
if requestBody.RequiredQuantity != nil {
existing.RequiredQuantity = *requestBody.RequiredQuantity
}
if requestBody.AllowAlternative != nil {
existing.AllowAlternative = *requestBody.AllowAlternative
}
if requestBody.PriorityOrder != nil {
existing.PriorityOrder = *requestBody.PriorityOrder
}
if requestBody.Note != "" {
existing.Note = requestBody.Note
}
invoiceConfigItem, err := repositories.UpdateInvoiceConfigItem(c.Request.Context(), global.Queries, existing)
if err != nil {
log.Error().Err(err).Msgf("Failed to update invoice config item with ID: %d", id)
response.InternalServerError(c, http.StatusInternalServerError, "Failed to update invoice config item")
return nil
}
response.Ok(c, "Invoice config item updated successfully", &responses.UpdateInvoiceConfigItemResponse{
ID: invoiceConfigItem.ID,
InvoiceConfigID: invoiceConfigItem.InvoiceConfigID,
ComponentID: invoiceConfigItem.ComponentID,
RequiredQuantity: invoiceConfigItem.RequiredQuantity,
AllowAlternative: invoiceConfigItem.AllowAlternative,
PriorityOrder: invoiceConfigItem.PriorityOrder,
Note: invoiceConfigItem.Note,
})
return nil
}
// InvoiceConfigItemDelete deletes an invoice config item by its ID.
//
// @Summary Delete invoice config item
// @Description Delete an invoice config item by its unique identifier
// @Tags invoice-config-item
// @Accept json
// @Produce json
// @Param id path int true "Invoice config item ID"
// @Success 200 {object} response.SuccessResponse
// @Failure 400 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /v1/invoice-config-items/{id} [delete]
func InvoiceConfigItemDelete(c *gin.Context) error {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequestError(c, http.StatusBadRequest, "Invalid ID")
return nil
}
rowsAffected, err := repositories.DeleteInvoiceConfigItem(c.Request.Context(), global.Queries, id)
if err != nil {
log.Error().Err(err).Msgf("Failed to delete invoice config item with ID: %d", id)
response.InternalServerError(c, http.StatusInternalServerError, "Failed to delete invoice config item")
return nil
}
if rowsAffected == 0 {
response.NotFoundError(c, http.StatusNotFound, "Invoice config item not found")
return nil
}
response.Ok(c, "Delete Success", nil)
return nil
}

View File

@@ -0,0 +1,170 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: invoice_config_item.sql
package db
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const createInvoiceConfigItem = `-- name: CreateInvoiceConfigItem :one
INSERT INTO invoice_config_items (invoice_config_id,component_id,required_quantity, allow_alternative,priority_order, note, metadata)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
)
RETURNING id, invoice_config_id, component_id, required_quantity, allow_alternative, priority_order, note, metadata
`
type CreateInvoiceConfigItemParams struct {
InvoiceConfigID int64 `db:"invoice_config_id" json:"invoiceConfigId"`
ComponentID int64 `db:"component_id" json:"componentId"`
RequiredQuantity int32 `db:"required_quantity" json:"requiredQuantity"`
AllowAlternative bool `db:"allow_alternative" json:"allowAlternative"`
PriorityOrder int32 `db:"priority_order" json:"priorityOrder"`
Note pgtype.Text `db:"note" json:"note"`
Metadata []byte `db:"metadata" json:"metadata"`
}
func (q *Queries) CreateInvoiceConfigItem(ctx context.Context, arg CreateInvoiceConfigItemParams) (InvoiceConfigItem, error) {
row := q.db.QueryRow(ctx, createInvoiceConfigItem,
arg.InvoiceConfigID,
arg.ComponentID,
arg.RequiredQuantity,
arg.AllowAlternative,
arg.PriorityOrder,
arg.Note,
arg.Metadata,
)
var i InvoiceConfigItem
err := row.Scan(
&i.ID,
&i.InvoiceConfigID,
&i.ComponentID,
&i.RequiredQuantity,
&i.AllowAlternative,
&i.PriorityOrder,
&i.Note,
&i.Metadata,
)
return i, err
}
const deleteInvoiceConfigItem = `-- name: DeleteInvoiceConfigItem :execrows
DELETE FROM invoice_config_items
WHERE id = $1
`
func (q *Queries) DeleteInvoiceConfigItem(ctx context.Context, id int64) (int64, error) {
result, err := q.db.Exec(ctx, deleteInvoiceConfigItem, id)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const getInvoiceConfigItemByID = `-- name: GetInvoiceConfigItemByID :one
SELECT id, invoice_config_id, component_id, required_quantity, allow_alternative, priority_order, note, metadata FROM invoice_config_items
WHERE id = $1
`
func (q *Queries) GetInvoiceConfigItemByID(ctx context.Context, id int64) (InvoiceConfigItem, error) {
row := q.db.QueryRow(ctx, getInvoiceConfigItemByID, id)
var i InvoiceConfigItem
err := row.Scan(
&i.ID,
&i.InvoiceConfigID,
&i.ComponentID,
&i.RequiredQuantity,
&i.AllowAlternative,
&i.PriorityOrder,
&i.Note,
&i.Metadata,
)
return i, err
}
const listInvoiceConfigItems = `-- name: ListInvoiceConfigItems :many
SELECT id, invoice_config_id, component_id, required_quantity, allow_alternative, priority_order, note, metadata FROM invoice_config_items
`
func (q *Queries) ListInvoiceConfigItems(ctx context.Context) ([]InvoiceConfigItem, error) {
rows, err := q.db.Query(ctx, listInvoiceConfigItems)
if err != nil {
return nil, err
}
defer rows.Close()
var items []InvoiceConfigItem
for rows.Next() {
var i InvoiceConfigItem
if err := rows.Scan(
&i.ID,
&i.InvoiceConfigID,
&i.ComponentID,
&i.RequiredQuantity,
&i.AllowAlternative,
&i.PriorityOrder,
&i.Note,
&i.Metadata,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateInvoiceConfigItem = `-- name: UpdateInvoiceConfigItem :one
UPDATE invoice_config_items
SET required_quantity = coalesce($1, required_quantity),
allow_alternative = coalesce($2, allow_alternative),
priority_order = coalesce($3, priority_order),
note = coalesce($4, note),
metadata = coalesce($5, metadata)
WHERE id = $6
RETURNING id, invoice_config_id, component_id, required_quantity, allow_alternative, priority_order, note, metadata
`
type UpdateInvoiceConfigItemParams struct {
RequiredQuantity int32 `db:"required_quantity" json:"requiredQuantity"`
AllowAlternative bool `db:"allow_alternative" json:"allowAlternative"`
PriorityOrder int32 `db:"priority_order" json:"priorityOrder"`
Note pgtype.Text `db:"note" json:"note"`
Metadata []byte `db:"metadata" json:"metadata"`
ID int64 `db:"id" json:"id"`
}
func (q *Queries) UpdateInvoiceConfigItem(ctx context.Context, arg UpdateInvoiceConfigItemParams) (InvoiceConfigItem, error) {
row := q.db.QueryRow(ctx, updateInvoiceConfigItem,
arg.RequiredQuantity,
arg.AllowAlternative,
arg.PriorityOrder,
arg.Note,
arg.Metadata,
arg.ID,
)
var i InvoiceConfigItem
err := row.Scan(
&i.ID,
&i.InvoiceConfigID,
&i.ComponentID,
&i.RequiredQuantity,
&i.AllowAlternative,
&i.PriorityOrder,
&i.Note,
&i.Metadata,
)
return i, err
}

View File

@@ -21,6 +21,7 @@ type Querier interface {
CreateComponentType(ctx context.Context, arg CreateComponentTypeParams) (ComponentType, error)
CreateContainer(ctx context.Context, arg CreateContainerParams) (Container, error)
CreateInvoiceConfig(ctx context.Context, arg CreateInvoiceConfigParams) (InvoiceConfig, error)
CreateInvoiceConfigItem(ctx context.Context, arg CreateInvoiceConfigItemParams) (InvoiceConfigItem, error)
CreateRole(ctx context.Context, arg CreateRoleParams) (Role, error)
CreateRoom(ctx context.Context, arg CreateRoomParams) (Room, error)
CreateShelve(ctx context.Context, arg CreateShelveParams) (Shelf, error)
@@ -33,6 +34,7 @@ type Querier interface {
DeleteComponentType(ctx context.Context, id int64) (int64, error)
DeleteContainer(ctx context.Context, id int64) (int64, error)
DeleteInvoiceConfig(ctx context.Context, id int64) (int64, error)
DeleteInvoiceConfigItem(ctx context.Context, id int64) (int64, error)
DeleteRole(ctx context.Context, id uuid.UUID) (int64, error)
DeleteRoom(ctx context.Context, id int64) (int64, error)
DeleteShelve(ctx context.Context, id int64) (int64, error)
@@ -46,6 +48,7 @@ type Querier interface {
GetComponentTypeByID(ctx context.Context, id int64) (ComponentType, error)
GetContainerByID(ctx context.Context, id int64) (Container, error)
GetInvoiceConfigByID(ctx context.Context, id int64) (InvoiceConfig, error)
GetInvoiceConfigItemByID(ctx context.Context, id int64) (InvoiceConfigItem, error)
GetRoleByID(ctx context.Context, id uuid.UUID) (Role, error)
GetRoomByID(ctx context.Context, id int64) (Room, error)
GetShelveByID(ctx context.Context, id int64) (Shelf, error)
@@ -62,6 +65,7 @@ type Querier interface {
ListComponentTypes(ctx context.Context) ([]ComponentType, error)
ListComponents(ctx context.Context) ([]Component, error)
ListContainers(ctx context.Context) ([]Container, error)
ListInvoiceConfigItems(ctx context.Context) ([]InvoiceConfigItem, error)
ListInvoiceConfigs(ctx context.Context) ([]InvoiceConfig, error)
ListRoles(ctx context.Context) ([]Role, error)
ListRooms(ctx context.Context) ([]Room, error)
@@ -78,6 +82,7 @@ type Querier interface {
UpdateComponentType(ctx context.Context, arg UpdateComponentTypeParams) (ComponentType, error)
UpdateContainer(ctx context.Context, arg UpdateContainerParams) (Container, error)
UpdateInvoiceConfig(ctx context.Context, arg UpdateInvoiceConfigParams) (InvoiceConfig, error)
UpdateInvoiceConfigItem(ctx context.Context, arg UpdateInvoiceConfigItemParams) (InvoiceConfigItem, error)
UpdateRole(ctx context.Context, arg UpdateRoleParams) (Role, error)
UpdateRoom(ctx context.Context, arg UpdateRoomParams) (Room, error)
UpdateShelve(ctx context.Context, arg UpdateShelveParams) (Shelf, error)