name: CI/CD - ERP Core Monorepo
on:
pull_request:
branches:
- production
types:
- closed
jobs:
backend-build-and-deploy:
name: Build & Deploy ERP Core Backend
runs-on: linux
if: github.event.pull_request.merged == true
steps:
- name: Checkout code
run: |
git clone \
--depth 1 \
--branch production \
https://oauth2:${{ secrets.ERPCORE }}@gitea.hexdive.com/New_REP_SYSTEM/ERP-core.git \
.
- name: Restore backend
run: dotnet restore Backend/ERPCore.sln
- name: Publish backend
run: |
rm -rf /tmp/erpcore-deploy
mkdir -p /tmp/erpcore-deploy
dotnet publish Backend/ERPCore/ERPCore.csproj \
-c Release \
-r linux-x64 \
--self-contained true \
-o /tmp/erpcore-deploy
- name: Stop backend service
run: systemctl stop erpcore.service
- name: Copy backend to deploy folder
run: |
mkdir -p /home/erp/core/publish
rm -rf /home/erp/core/publish/*
cp -r /tmp/erpcore-deploy/* /home/erp/core/publish/
- name: Fix backend ownership and permissions
run: |
chown -R erpuser:erpuser /home/erp/core/publish
find /home/erp/core/publish -type d -exec chmod 755 {} +
find /home/erp/core/publish -type f -exec chmod 644 {} +
chmod +x /home/erp/core/publish/ERPCore
- name: Restart backend service
run: systemctl restart erpcore.service
- name: Verify backend
run: |
systemctl is-active erpcore.service && echo "Backend service running" || echo "Backend service failed"
frontend-build-and-deploy:
name: Build & Deploy ERP Core Frontend
runs-on: linux
needs: backend-build-and-deploy
if: github.event.pull_request.merged == true
steps:
- name: Checkout code
run: |
git clone \
--depth 1 \
--branch Production \
https://oauth2:${{ secrets.ERPCORE }}@gitea.hexdive.com/New_REP_SYSTEM/ERP-core.git \
.
- name: Build frontend Docker image
run: docker build -t erpcore-frontend:latest Frontend/erp-system
- name: Stop & remove existing frontend container
run: |
docker stop erpcore-frontend 2>/dev/null || true
docker rm erpcore-frontend 2>/dev/null || true
- name: Start frontend container
run: |
docker run -d \
--name erpcore-frontend \
-p 6702:6702 \
--add-host=host.docker.internal:host-gateway \
-e BACKEND_ORIGIN=http://host.docker.internal:6701 \
--restart unless-stopped \
--memory="512m" \
--cpus="1.0" \
--cap-drop ALL \
--security-opt no-new-privileges \
erpcore-frontend:latest
- name: Remove old frontend images
run: docker image prune -f
- name: Verify frontend
run: |
docker ps --filter name=erpcore-frontend --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" \
| grep erpcore-frontend && echo "Frontend container running" || echo "Frontend container failed"
This commit is contained in:
@@ -8,7 +8,7 @@ export { drivers, compliance } from './drivers'
|
||||
export { purchaseOrders, grn, purchaseReturns } from './procurement'
|
||||
export { rides, loadingSheets, deliveryTasks } from './operations'
|
||||
export { stock } from './stock'
|
||||
export { sales, orders, payments } from './sales'
|
||||
export { shopPos, invoices, payments } from './sales'
|
||||
export { saleReturns, claims, supplierClaims } from './returns-claims'
|
||||
export { getPaginatedItems } from './paginated'
|
||||
|
||||
|
||||
@@ -2,10 +2,8 @@ import { api } from '@/lib/api'
|
||||
import type {
|
||||
PaginatedResponse,
|
||||
RideResponse,
|
||||
CancelRequestResponse,
|
||||
LoadingSheetResponse,
|
||||
DeliveryTaskResponse,
|
||||
RideType,
|
||||
RideStatus,
|
||||
CancelRequestType,
|
||||
LoadingSheetStatus,
|
||||
@@ -16,22 +14,18 @@ import type { PageParams } from './master'
|
||||
// ─── Rides ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface RideBody {
|
||||
rideType: RideType
|
||||
vehicleId: string
|
||||
driverProfileId: string
|
||||
routeId: string
|
||||
sourceWarehouseId: string
|
||||
meterstart: number
|
||||
}
|
||||
|
||||
export interface RideListParams extends PageParams {
|
||||
status?: RideStatus
|
||||
rideType?: RideType
|
||||
driverProfileId?: string
|
||||
vehicleId?: string
|
||||
}
|
||||
|
||||
export interface CancelRequestBody {
|
||||
export interface CancelRideBody {
|
||||
typeCode: CancelRequestType
|
||||
reason: string
|
||||
}
|
||||
@@ -49,43 +43,24 @@ export const rides = {
|
||||
assignDriver: (id: string, driverProfileId: string) =>
|
||||
api.put<RideResponse>(`/rides/${id}/driver`, { driverProfileId }).then(r => r.data),
|
||||
|
||||
activate: (id: string) =>
|
||||
api.patch<RideResponse>(`/rides/${id}/activate`).then(r => r.data),
|
||||
|
||||
close: (id: string, meterend: number) =>
|
||||
api.patch<RideResponse>(`/rides/${id}/close`, { meterend }).then(r => r.data),
|
||||
api.post<RideResponse>(`/rides/${id}/close`, { meterend }).then(r => r.data),
|
||||
|
||||
cancelRequests: {
|
||||
getForRide: (rideId: string) =>
|
||||
api.get<CancelRequestResponse | null>(`/rides/${rideId}/cancel-request`).then(r => r.data),
|
||||
|
||||
raise: (rideId: string, body: CancelRequestBody) =>
|
||||
api.post<CancelRequestResponse>(`/rides/${rideId}/cancel-request`, body).then(r => r.data),
|
||||
|
||||
approve: (requestId: string) =>
|
||||
api.post<CancelRequestResponse>(`/rides/cancel-requests/${requestId}/approve`).then(r => r.data),
|
||||
|
||||
reject: (requestId: string) =>
|
||||
api.post<CancelRequestResponse>(`/rides/cancel-requests/${requestId}/reject`).then(r => r.data),
|
||||
},
|
||||
cancel: (id: string, body: CancelRideBody) =>
|
||||
api.post<RideResponse>(`/rides/${id}/cancel`, body).then(r => r.data),
|
||||
}
|
||||
|
||||
// ─── Loading Sheets ───────────────────────────────────────────────────────────
|
||||
|
||||
export interface LoadingSheetItemBody {
|
||||
itemId: string
|
||||
quantityDispatched: number
|
||||
export interface LoadingSheetCreateBody {
|
||||
fK_RideId: string
|
||||
}
|
||||
|
||||
export interface LoadingSheetBody {
|
||||
rideId: string
|
||||
sourceWarehouseId: string
|
||||
items: LoadingSheetItemBody[]
|
||||
}
|
||||
|
||||
export interface LoadingSheetReceiptItemBody {
|
||||
itemId: string
|
||||
quantityReceived: number
|
||||
export interface LoadingSheetItemInput {
|
||||
fK_ItemId: string
|
||||
fK_WarehouseId: string
|
||||
quantity: number
|
||||
fK_ShopPOItemId?: string | null
|
||||
}
|
||||
|
||||
export interface LoadingSheetListParams extends PageParams {
|
||||
@@ -100,17 +75,14 @@ export const loadingSheets = {
|
||||
get: (id: string) =>
|
||||
api.get<LoadingSheetResponse>(`/loading-sheets/${id}`).then(r => r.data),
|
||||
|
||||
create: (body: LoadingSheetBody) =>
|
||||
create: (body: LoadingSheetCreateBody) =>
|
||||
api.post<LoadingSheetResponse>('/loading-sheets', body).then(r => r.data),
|
||||
|
||||
confirmDispatch: (id: string) =>
|
||||
api.patch<LoadingSheetResponse>(`/loading-sheets/${id}/dispatch`).then(r => r.data),
|
||||
updateItems: (id: string, items: LoadingSheetItemInput[]) =>
|
||||
api.put<LoadingSheetResponse>(`/loading-sheets/${id}/items`, { items }).then(r => r.data),
|
||||
|
||||
confirmReceipt: (id: string, items: LoadingSheetReceiptItemBody[]) =>
|
||||
api.patch<LoadingSheetResponse>(`/loading-sheets/${id}/receipt`, { items }).then(r => r.data),
|
||||
|
||||
resolve: (id: string) =>
|
||||
api.patch<LoadingSheetResponse>(`/loading-sheets/${id}/resolve`).then(r => r.data),
|
||||
confirm: (id: string) =>
|
||||
api.post<LoadingSheetResponse>(`/loading-sheets/${id}/confirm`).then(r => r.data),
|
||||
}
|
||||
|
||||
// ─── Delivery Tasks ───────────────────────────────────────────────────────────
|
||||
@@ -121,11 +93,8 @@ export interface DeliveryTaskItemQuantity {
|
||||
}
|
||||
|
||||
export const deliveryTasks = {
|
||||
generate: (rideId: string) =>
|
||||
api.post<DeliveryTaskResponse[]>(`/rides/${rideId}/tasks/generate`).then(r => r.data),
|
||||
|
||||
listByRide: (rideId: string) =>
|
||||
api.get<DeliveryTaskResponse[]>(`/rides/${rideId}/delivery-tasks`).then(r => r.data),
|
||||
api.get<DeliveryTaskResponse[]>(`/rides/${rideId}/tasks`).then(r => r.data),
|
||||
|
||||
get: (id: string) =>
|
||||
api.get<DeliveryTaskResponse>(`/delivery-tasks/${id}`).then(r => r.data),
|
||||
|
||||
@@ -35,11 +35,11 @@ export const saleReturns = {
|
||||
get: (id: string) =>
|
||||
api.get<SaleReturnResponse>(`/returns/${id}`).then(r => r.data),
|
||||
|
||||
listByOrder: (orderId: string) =>
|
||||
api.get<SaleReturnResponse[]>(`/orders/${orderId}/returns`).then(r => r.data),
|
||||
listByShopPO: (shopPOId: string) =>
|
||||
api.get<SaleReturnResponse[]>(`/shop-pos/${shopPOId}/returns`).then(r => r.data),
|
||||
|
||||
create: (orderId: string, body: SaleReturnBody) =>
|
||||
api.post<SaleReturnResponse>(`/orders/${orderId}/returns`, body).then(r => r.data),
|
||||
create: (shopPOId: string, body: SaleReturnBody) =>
|
||||
api.post<SaleReturnResponse>(`/shop-pos/${shopPOId}/returns`, body).then(r => r.data),
|
||||
|
||||
updateReasons: (id: string, body: UpdateSaleReturnReasonsBody) =>
|
||||
api.patch<SaleReturnResponse>(`/returns/${id}/reasons`, body).then(r => r.data),
|
||||
|
||||
@@ -1,101 +1,99 @@
|
||||
import { api } from '@/lib/api'
|
||||
import type {
|
||||
PaginatedResponse,
|
||||
SaleResponse,
|
||||
OrderResponse,
|
||||
OrderStatus,
|
||||
ShopPOResponse,
|
||||
InvoiceResponse,
|
||||
InvoiceStatus,
|
||||
PaymentResponse,
|
||||
SaleStatus,
|
||||
PaymentStatus,
|
||||
PaymentMethod,
|
||||
ShopPOStatus,
|
||||
} from '@/types/api'
|
||||
|
||||
import type { PageParams } from './master'
|
||||
|
||||
// ─── Sales ────────────────────────────────────────────────────────────────────
|
||||
// ─── Shop POs ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface SaleItemBody {
|
||||
export interface ShopPOItemBody {
|
||||
itemId: string
|
||||
quantity: number
|
||||
unitPrice: number
|
||||
unitPrice?: number | null
|
||||
}
|
||||
|
||||
export interface SaleBody {
|
||||
export interface CreateShopPOBody {
|
||||
storeId: string
|
||||
saleDate: string
|
||||
rideId?: string | null
|
||||
fulfillImmediately?: boolean
|
||||
items: SaleItemBody[]
|
||||
// TEMPORARY: required while auth doesn't resolve a logged-in user server-side — see testbug.md #28.
|
||||
createdByUserId: string
|
||||
items: ShopPOItemBody[]
|
||||
}
|
||||
|
||||
export interface SaleListParams extends PageParams {
|
||||
storeId?: string
|
||||
status?: SaleStatus
|
||||
paymentStatus?: PaymentStatus
|
||||
rideId?: string
|
||||
from?: string
|
||||
to?: string
|
||||
export interface UpdateShopPOItemsBody {
|
||||
items: ShopPOItemBody[]
|
||||
}
|
||||
|
||||
export const sales = {
|
||||
list: (params?: SaleListParams) =>
|
||||
api.get<PaginatedResponse<SaleResponse>>('/sales', { params }).then(r => r.data),
|
||||
export interface ShopPOListParams extends PageParams {
|
||||
agentId?: string
|
||||
routeId?: string
|
||||
shopId?: string
|
||||
confirmed?: boolean
|
||||
status?: ShopPOStatus
|
||||
}
|
||||
|
||||
export const shopPos = {
|
||||
list: (params?: ShopPOListParams) =>
|
||||
api.get<PaginatedResponse<ShopPOResponse>>('/shop-pos', { params }).then(r => r.data),
|
||||
|
||||
get: (id: string) =>
|
||||
api.get<SaleResponse>(`/sales/${id}`).then(r => r.data),
|
||||
api.get<ShopPOResponse>(`/shop-pos/${id}`).then(r => r.data),
|
||||
|
||||
create: (body: SaleBody) =>
|
||||
api.post<SaleResponse>('/sales', body).then(r => r.data),
|
||||
create: (body: CreateShopPOBody) =>
|
||||
api.post<ShopPOResponse>('/shop-pos', body).then(r => r.data),
|
||||
|
||||
updateItems: (id: string, body: UpdateShopPOItemsBody) =>
|
||||
api.put<ShopPOResponse>(`/shop-pos/${id}/items`, body).then(r => r.data),
|
||||
|
||||
confirm: (id: string) =>
|
||||
api.post<ShopPOResponse>(`/shop-pos/${id}/confirm`).then(r => r.data),
|
||||
|
||||
confirmAndCreateInvoice: (id: string) =>
|
||||
api.post<ShopPOResponse>(`/shop-pos/${id}/confirm-and-create-invoice`).then(r => r.data),
|
||||
|
||||
cancel: (id: string) =>
|
||||
api.patch<SaleResponse>(`/sales/${id}/cancel`).then(r => r.data),
|
||||
api.post<ShopPOResponse>(`/shop-pos/${id}/cancel`).then(r => r.data),
|
||||
}
|
||||
|
||||
// ─── Orders ───────────────────────────────────────────────────────────────────
|
||||
// GET /orders takes no query params and returns a plain array — no server-side
|
||||
// filtering/pagination exists on the backend, unlike Sales/Payments.
|
||||
// ─── Invoices ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export const orders = {
|
||||
list: () =>
|
||||
api.get<OrderResponse[]>('/orders').then(r => r.data),
|
||||
export interface InvoiceListParams extends PageParams {
|
||||
agentId?: string
|
||||
routeId?: string
|
||||
shopId?: string
|
||||
status?: InvoiceStatus
|
||||
}
|
||||
|
||||
export const invoices = {
|
||||
list: (params?: InvoiceListParams) =>
|
||||
api.get<PaginatedResponse<InvoiceResponse>>('/invoices', { params }).then(r => r.data),
|
||||
|
||||
get: (id: string) =>
|
||||
api.get<OrderResponse>(`/orders/${id}`).then(r => r.data),
|
||||
api.get<InvoiceResponse>(`/invoices/${id}`).then(r => r.data),
|
||||
|
||||
update: (id: string, status: OrderStatus) =>
|
||||
api.put<OrderResponse>(`/orders/${id}`, { status }).then(r => r.data),
|
||||
print: (id: string) =>
|
||||
api.post<InvoiceResponse>(`/invoices/${id}/print`).then(r => r.data),
|
||||
|
||||
delete: (id: string) =>
|
||||
api.delete(`/orders/${id}`),
|
||||
finalize: (id: string) =>
|
||||
api.post<InvoiceResponse>(`/invoices/${id}/finalize`).then(r => r.data),
|
||||
}
|
||||
|
||||
// ─── Payments ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface PaymentBody {
|
||||
saleId: string
|
||||
amount: number
|
||||
method: PaymentMethod
|
||||
// TEMPORARY: required while auth doesn't resolve a logged-in user server-side — see testbug.md #28.
|
||||
collectedByUserId: string
|
||||
}
|
||||
|
||||
export interface PaymentListParams extends PageParams {
|
||||
storeId?: string
|
||||
saleId?: string
|
||||
method?: PaymentMethod
|
||||
from?: string
|
||||
to?: string
|
||||
collectedByUserId?: string | null
|
||||
}
|
||||
|
||||
export const payments = {
|
||||
list: (params?: PaymentListParams) =>
|
||||
api.get<PaginatedResponse<PaymentResponse>>('/payments', { params }).then(r => r.data),
|
||||
listByInvoice: (invoiceId: string) =>
|
||||
api.get<PaymentResponse[]>(`/invoices/${invoiceId}/payments`).then(r => r.data),
|
||||
|
||||
get: (id: string) =>
|
||||
api.get<PaymentResponse>(`/payments/${id}`).then(r => r.data),
|
||||
|
||||
create: (body: PaymentBody) =>
|
||||
api.post<PaymentResponse>('/payments', body).then(r => r.data),
|
||||
create: (invoiceId: string, body: PaymentBody) =>
|
||||
api.post<PaymentResponse>(`/invoices/${invoiceId}/payments`, body).then(r => r.data),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user