feat: add REQ0187 frontend party-order CRUD functionality and backend API endpoints
This commit is contained in:
18
01_Requirements/REQ0187/index.md
Normal file
18
01_Requirements/REQ0187/index.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
tags: frontend, party-order
|
||||||
|
---
|
||||||
|
|
||||||
|
# REQ0185 frontend party-order
|
||||||
|
|
||||||
|
frontend page to handle party-order (CRUD)
|
||||||
|
|
||||||
|
edit page T.B.A.
|
||||||
|
|
||||||
|
## sources
|
||||||
|
|
||||||
|
T.B.A.
|
||||||
|
|
||||||
|
## branch
|
||||||
|
|
||||||
|
develop/frontend/party-order/trunk
|
||||||
|
develop/requirements/REQ0187
|
@@ -1230,3 +1230,30 @@ model AccessLog {
|
|||||||
@@index([timestamp])
|
@@index([timestamp])
|
||||||
@@index([userId])
|
@@index([userId])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model PartyOrderItem {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
//
|
||||||
|
taxes Float
|
||||||
|
status String
|
||||||
|
shipping Float
|
||||||
|
discount Float
|
||||||
|
subtotal Float
|
||||||
|
orderNumber String
|
||||||
|
totalAmount Float
|
||||||
|
totalQuantity Float
|
||||||
|
history Json
|
||||||
|
payment Json
|
||||||
|
customer Json
|
||||||
|
delivery Json
|
||||||
|
items Json[]
|
||||||
|
shippingAddress Json
|
||||||
|
// OrderProductItem OrderProductItem[]
|
||||||
|
// OrderHistory OrderHistory[]
|
||||||
|
// OrderDelivery OrderDelivery[]
|
||||||
|
// OrderCustomer OrderCustomer[]
|
||||||
|
// OrderPayment OrderPayment[]
|
||||||
|
// OrderShippingAddress OrderShippingAddress[]
|
||||||
|
}
|
||||||
|
@@ -31,6 +31,7 @@ import { EventReviewSeed } from './seeds/eventReview';
|
|||||||
import { appLogSeed } from './seeds/AppLog';
|
import { appLogSeed } from './seeds/AppLog';
|
||||||
import { accessLogSeed } from './seeds/AccessLog';
|
import { accessLogSeed } from './seeds/AccessLog';
|
||||||
import { userMetaSeed } from './seeds/userMeta';
|
import { userMetaSeed } from './seeds/userMeta';
|
||||||
|
import { partyOrderItemSeed } from './seeds/partyOrderItem';
|
||||||
|
|
||||||
//
|
//
|
||||||
// import { Blog } from './seeds/blog';
|
// import { Blog } from './seeds/blog';
|
||||||
@@ -60,6 +61,8 @@ import { userMetaSeed } from './seeds/userMeta';
|
|||||||
await appLogSeed;
|
await appLogSeed;
|
||||||
await accessLogSeed;
|
await accessLogSeed;
|
||||||
|
|
||||||
|
await partyOrderItemSeed;
|
||||||
|
|
||||||
// await Blog;
|
// await Blog;
|
||||||
// await Mail;
|
// await Mail;
|
||||||
// await File;
|
// await File;
|
||||||
|
94
03_source/cms_backend/prisma/seeds/partyOrderItem.ts
Normal file
94
03_source/cms_backend/prisma/seeds/partyOrderItem.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import { _mock } from './_mock';
|
||||||
|
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
const ITEMS = Array.from({ length: 3 }, (_, index) => ({
|
||||||
|
id: _mock.id(index),
|
||||||
|
sku: `16H9UR${index}`,
|
||||||
|
quantity: index + 1,
|
||||||
|
name: _mock.productName(index),
|
||||||
|
coverUrl: _mock.image.product(index),
|
||||||
|
price: _mock.number.price(index),
|
||||||
|
}));
|
||||||
|
|
||||||
|
async function partyOrderItem() {
|
||||||
|
await prisma.partyOrderItem.deleteMany({});
|
||||||
|
|
||||||
|
for (let index = 1; index < 20 + 1; index++) {
|
||||||
|
const shipping = 10;
|
||||||
|
const discount = 10;
|
||||||
|
const taxes = 10;
|
||||||
|
const items = (index % 2 && ITEMS.slice(0, 1)) || (index % 3 && ITEMS.slice(1, 3)) || ITEMS;
|
||||||
|
const totalQuantity = items.reduce((accumulator, item) => accumulator + item.quantity, 0);
|
||||||
|
const subtotal = items.reduce((accumulator, item) => accumulator + item.price * item.quantity, 0);
|
||||||
|
const totalAmount = subtotal - shipping - discount + taxes;
|
||||||
|
|
||||||
|
const customer = {
|
||||||
|
id: _mock.id(index),
|
||||||
|
name: _mock.fullName(index),
|
||||||
|
email: _mock.email(index),
|
||||||
|
avatarUrl: _mock.image.avatar(index),
|
||||||
|
ipAddress: '192.158.1.38',
|
||||||
|
};
|
||||||
|
|
||||||
|
const delivery = { shipBy: 'DHL', speedy: 'Standard', trackingNumber: 'SPX037739199373' };
|
||||||
|
|
||||||
|
const history = {
|
||||||
|
orderTime: _mock.time(1),
|
||||||
|
paymentTime: _mock.time(2),
|
||||||
|
deliveryTime: _mock.time(3),
|
||||||
|
completionTime: _mock.time(4),
|
||||||
|
timeline: [
|
||||||
|
{ title: 'Delivery successful', time: _mock.time(1) },
|
||||||
|
{ title: 'Transporting to [2]', time: _mock.time(2) },
|
||||||
|
{ title: 'Transporting to [1]', time: _mock.time(3) },
|
||||||
|
{ title: 'The shipping unit has picked up the goods', time: _mock.time(4) },
|
||||||
|
{ title: 'Order has been created', time: _mock.time(5) },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const temp = await prisma.partyOrderItem.upsert({
|
||||||
|
where: { id: index.toString() },
|
||||||
|
update: {},
|
||||||
|
create: {
|
||||||
|
id: _mock.id(index),
|
||||||
|
orderNumber: `#601${index}`,
|
||||||
|
taxes,
|
||||||
|
items,
|
||||||
|
history,
|
||||||
|
subtotal: items.reduce((accumulator, item) => accumulator + item.price * item.quantity, 0),
|
||||||
|
shipping,
|
||||||
|
discount,
|
||||||
|
customer,
|
||||||
|
delivery,
|
||||||
|
totalAmount,
|
||||||
|
totalQuantity,
|
||||||
|
shippingAddress: {
|
||||||
|
fullAddress: '19034 Verna Unions Apt. 164 - Honolulu, RI / 87535',
|
||||||
|
phoneNumber: '365-374-4961',
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
//
|
||||||
|
cardType: 'mastercard',
|
||||||
|
cardNumber: '4111 1111 1111 1111',
|
||||||
|
},
|
||||||
|
status: (index % 2 && 'completed') || (index % 3 && 'pending') || (index % 4 && 'cancelled') || 'refunded',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('seed partyOrderItemSeed done');
|
||||||
|
}
|
||||||
|
|
||||||
|
const partyOrderItemSeed = partyOrderItem()
|
||||||
|
.then(async () => {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
})
|
||||||
|
.catch(async (e) => {
|
||||||
|
console.error(e);
|
||||||
|
await prisma.$disconnect();
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
export { partyOrderItemSeed };
|
14
03_source/cms_backend/src/app/api/_PROMPTS/clone_srevice.md
Normal file
14
03_source/cms_backend/src/app/api/_PROMPTS/clone_srevice.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Hi,
|
||||||
|
|
||||||
|
i copied from
|
||||||
|
`03_source/cms_backend/src/app/api/party-event`
|
||||||
|
to
|
||||||
|
`03_source/cms_backend/src/app/api/party-order`
|
||||||
|
|
||||||
|
with knowledge in `schema.prisma` file, and take a look into the sibling files in the same directory.
|
||||||
|
|
||||||
|
i want you to update `03_source/cms_backend/src/app/api/party-order` content to handle `party-order` (the purchase order of the party)
|
||||||
|
`party-order.service.ts` is already prepared and you can use it
|
||||||
|
please maintain same format and level of detail when you edit.
|
||||||
|
|
||||||
|
thanks.
|
35
03_source/cms_backend/src/app/api/party-event/_GUIDELINES.md
Normal file
35
03_source/cms_backend/src/app/api/party-event/_GUIDELINES.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!-- AI: please maintain same format and level of detail when edit this file -->
|
||||||
|
|
||||||
|
# GUIDELINE
|
||||||
|
|
||||||
|
- Party Event API endpoint for managing party events
|
||||||
|
- Handles CRUD operations for party events
|
||||||
|
- Follows single file for single db table/collection pattern
|
||||||
|
|
||||||
|
## `route.ts`
|
||||||
|
|
||||||
|
Handles HTTP methods:
|
||||||
|
|
||||||
|
- `GET` - Retrieve party events
|
||||||
|
- `POST` - Create new party event
|
||||||
|
- `PUT` - Update existing party event
|
||||||
|
- `DELETE` - Remove party event
|
||||||
|
|
||||||
|
## `test.http`
|
||||||
|
|
||||||
|
Contains test requests for:
|
||||||
|
|
||||||
|
- Listing all party events
|
||||||
|
- Creating new party event
|
||||||
|
- Updating existing party event
|
||||||
|
- Deleting party event
|
||||||
|
|
||||||
|
## `../../services/party-event.service.ts`
|
||||||
|
|
||||||
|
Party Event CRUD operations:
|
||||||
|
|
||||||
|
`listPartyEvents` - List all party events with optional filters
|
||||||
|
`getPartyEvent` - Get single party event by ID
|
||||||
|
`createNewPartyEvent` - Create new party event record
|
||||||
|
`updatePartyEvent` - Update existing party event by ID
|
||||||
|
`deletePartyEvent` - Delete party event by ID
|
35
03_source/cms_backend/src/app/api/party-order/_GUIDELINES.md
Normal file
35
03_source/cms_backend/src/app/api/party-order/_GUIDELINES.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!-- AI: please maintain same format and level of detail when edit this file -->
|
||||||
|
|
||||||
|
# GUIDELINE
|
||||||
|
|
||||||
|
- Party Order API endpoint for managing party orders
|
||||||
|
- Handles CRUD operations for party orders
|
||||||
|
- Follows single file for single db table/collection pattern
|
||||||
|
|
||||||
|
## `route.ts`
|
||||||
|
|
||||||
|
Handles HTTP methods:
|
||||||
|
|
||||||
|
- `GET` - Retrieve party orders
|
||||||
|
- `POST` - Create new party order
|
||||||
|
- `PUT` - Update existing party order
|
||||||
|
- `DELETE` - Remove party order
|
||||||
|
|
||||||
|
## `test.http`
|
||||||
|
|
||||||
|
Contains test requests for:
|
||||||
|
|
||||||
|
- Listing all party orders
|
||||||
|
- Creating new party order
|
||||||
|
- Updating existing party order
|
||||||
|
- Deleting party order
|
||||||
|
|
||||||
|
## `../../services/party-order.service.ts`
|
||||||
|
|
||||||
|
Party Order CRUD operations:
|
||||||
|
|
||||||
|
`listPartyOrders` - List all party orders with optional filters
|
||||||
|
`getPartyOrder` - Get single party order by ID
|
||||||
|
`createNewPartyOrder` - Create new party order record
|
||||||
|
`updatePartyOrder` - Update existing party order by ID
|
||||||
|
`deletePartyOrder` - Delete party order by ID
|
@@ -0,0 +1,40 @@
|
|||||||
|
// src/app/api/party-order/create/route.ts
|
||||||
|
//
|
||||||
|
// PURPOSE:
|
||||||
|
// Create new party order in db
|
||||||
|
//
|
||||||
|
// RULES:
|
||||||
|
// T.B.A.
|
||||||
|
|
||||||
|
import type { NextRequest } from 'next/server';
|
||||||
|
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
import { isDev } from 'src/constants';
|
||||||
|
import { createOrder } from 'src/app/services/party-order.service';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** **************************************
|
||||||
|
* POST - Create PartyOrder
|
||||||
|
*************************************** */
|
||||||
|
export async function POST(req: NextRequest) {
|
||||||
|
const { partyOrderData } = await req.json();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isDev) {
|
||||||
|
console.log({ partyOrderData });
|
||||||
|
}
|
||||||
|
|
||||||
|
const created = await createOrder(partyOrderData);
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
console.log('Order created successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response(created, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating order:', { partyOrderData });
|
||||||
|
return handleError('PartyOrder - Create', error);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
###
|
||||||
|
|
||||||
|
POST http://localhost:7272/api/party-order/create
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"partyOrderData": {
|
||||||
|
"taxes": 15.00,
|
||||||
|
"status": "pending",
|
||||||
|
"shipping": 10.00,
|
||||||
|
"discount": 20.00,
|
||||||
|
"subtotal": 290.00,
|
||||||
|
"orderNumber": "ORD_20231115001",
|
||||||
|
"totalAmount": 300.00,
|
||||||
|
"totalQuantity": 2.0,
|
||||||
|
"history": "{\"actions\":[{\"timestamp\":\"2023-11-15T10:00:00Z\",\"action\":\"order_created\"}]}",
|
||||||
|
"payment": "{\"method\":\"credit_card\",\"status\":\"unpaid\",\"transaction_id\":\"txn_123456\"}",
|
||||||
|
"customer": "{\"name\":\"John Doe\",\"email\":\"john.doe@example.com\",\"phone\":\"+1234567890\"}",
|
||||||
|
"delivery": "{\"method\":\"courier\",\"estimated_delivery\":\"2023-11-18\"}",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "ticket_001",
|
||||||
|
"name": "General Admission",
|
||||||
|
"quantity": 2,
|
||||||
|
"price": 150.00
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"shippingAddress": "{\"street\":\"123 Main St\",\"city\":\"New York\",\"state\":\"NY\",\"zip\":\"10001\",\"country\":\"USA\"}"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
import type { NextRequest } from 'next/server';
|
||||||
|
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
import { deleteOrder } from 'src/app/services/party-order.service';
|
||||||
|
|
||||||
|
/** **************************************
|
||||||
|
* PATCH - Delete PartyOrder
|
||||||
|
*************************************** */
|
||||||
|
export async function PATCH(req: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { orderId } = await req.json();
|
||||||
|
|
||||||
|
if (!orderId) throw new Error('orderId cannot be null');
|
||||||
|
|
||||||
|
await deleteOrder(orderId);
|
||||||
|
|
||||||
|
return response({ orderId }, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
return handleError('PartyOrder - Delete', error);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,8 @@
|
|||||||
|
###
|
||||||
|
|
||||||
|
PATCH http://localhost:7272/api/party-order/delete
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"orderId": "e99f09a7-dd88-49d5-b1c8-1daf80c2d7b02"
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
// src/app/api/party-order/details/route.ts
|
||||||
|
//
|
||||||
|
// PURPOSE:
|
||||||
|
// Get party order from db by id
|
||||||
|
//
|
||||||
|
// RULES:
|
||||||
|
// Do not modify the format and level of details thanks.
|
||||||
|
|
||||||
|
import type { NextRequest } from 'next/server';
|
||||||
|
|
||||||
|
import { logger } from 'src/utils/logger';
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
import { L_INFO, L_ERROR } from 'src/constants';
|
||||||
|
import { getOrder } from 'src/app/services/party-order.service';
|
||||||
|
import { createAppLog } from 'src/app/services/app-log.service';
|
||||||
|
|
||||||
|
import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
**************************************
|
||||||
|
* GET PartyOrder detail
|
||||||
|
***************************************
|
||||||
|
*/
|
||||||
|
export async function GET(req: NextRequest) {
|
||||||
|
const debug = { 'req.headers': flattenNextjsRequest(req) };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { searchParams } = req.nextUrl;
|
||||||
|
|
||||||
|
// RULES: partyOrderId must exist
|
||||||
|
const partyOrderId = searchParams.get('partyOrderId');
|
||||||
|
if (!partyOrderId) {
|
||||||
|
return response({ message: 'Order ID is required!' }, STATUS.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: partyOrderId confirmed exist, run below
|
||||||
|
const order = await getOrder(partyOrderId);
|
||||||
|
|
||||||
|
if (!order) {
|
||||||
|
return response({ message: 'Order not found!' }, STATUS.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger('[PartyOrder] details', order.id);
|
||||||
|
|
||||||
|
createAppLog(L_INFO, 'Get order detail OK', debug);
|
||||||
|
|
||||||
|
return response({ order }, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
createAppLog(L_ERROR, 'order detail error', debug);
|
||||||
|
|
||||||
|
return handleError('PartyOrder - Get details', error);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
###
|
||||||
|
|
||||||
|
# Get details for a specific party order
|
||||||
|
GET http://localhost:7272/api/party-order/details?partyOrderId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b02
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# Alternative format with different ID
|
||||||
|
GET http://localhost:7272/api/party-order/details?id=ord_987654321
|
@@ -0,0 +1,16 @@
|
|||||||
|
import type { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
/**
|
||||||
|
***************************************
|
||||||
|
* GET - helloworld
|
||||||
|
***************************************
|
||||||
|
*/
|
||||||
|
export async function GET(req: NextRequest, res: NextResponse) {
|
||||||
|
try {
|
||||||
|
return response({ helloworld: 'party-order' }, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
return handleError('Helloworld - Get all', error);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,2 @@
|
|||||||
|
###
|
||||||
|
GET http://localhost:7272/api/party-order/helloworld
|
38
03_source/cms_backend/src/app/api/party-order/list/route.ts
Normal file
38
03_source/cms_backend/src/app/api/party-order/list/route.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// src/app/api/party-order/list/route.ts
|
||||||
|
//
|
||||||
|
// PURPOSE:
|
||||||
|
// List all party orders from db
|
||||||
|
//
|
||||||
|
// RULES:
|
||||||
|
// T.B.A.
|
||||||
|
|
||||||
|
import type { NextRequest } from 'next/server';
|
||||||
|
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
import { L_INFO, L_ERROR } from 'src/constants';
|
||||||
|
import { createAppLog } from 'src/app/services/app-log.service';
|
||||||
|
import { listPartyOrders } from 'src/app/services/party-order.service';
|
||||||
|
|
||||||
|
import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** **************************************
|
||||||
|
* GET - PartyOrders list
|
||||||
|
*************************************** */
|
||||||
|
export async function GET(req: NextRequest) {
|
||||||
|
const debug = { 'req.headers': flattenNextjsRequest(req) };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const orders = await listPartyOrders();
|
||||||
|
|
||||||
|
createAppLog(L_INFO, 'party-order list ok', {});
|
||||||
|
|
||||||
|
return response({ orders }, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
createAppLog(L_ERROR, 'party-order list error', debug);
|
||||||
|
|
||||||
|
return handleError('PartyOrder - Get list', error);
|
||||||
|
}
|
||||||
|
}
|
19
03_source/cms_backend/src/app/api/party-order/list/test.http
Normal file
19
03_source/cms_backend/src/app/api/party-order/list/test.http
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
###
|
||||||
|
|
||||||
|
# Basic list all orders
|
||||||
|
GET http://localhost:7272/api/party-order/list
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# List orders by status
|
||||||
|
GET http://localhost:7272/api/party-order/list?status=completed
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# List orders by user
|
||||||
|
GET http://localhost:7272/api/party-order/list?userId=usr_987654321
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# List orders by payment status
|
||||||
|
GET http://localhost:7272/api/party-order/list?paymentStatus=paid
|
75
03_source/cms_backend/src/app/api/party-order/route.ts
Normal file
75
03_source/cms_backend/src/app/api/party-order/route.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import type { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
import { listPartyOrders, deleteOrder, updateOrder, createOrder } from 'src/app/services/party-order.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
**************************************
|
||||||
|
* GET - PartyOrder
|
||||||
|
***************************************
|
||||||
|
*/
|
||||||
|
export async function GET(req: NextRequest, res: NextResponse) {
|
||||||
|
try {
|
||||||
|
const orders = await listPartyOrders();
|
||||||
|
return response(orders, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
return handleError('PartyOrder - Get list', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
***************************************
|
||||||
|
* POST - Create PartyOrder
|
||||||
|
***************************************
|
||||||
|
*/
|
||||||
|
export async function POST(req: NextRequest) {
|
||||||
|
const OPERATION = 'PartyOrder - Create';
|
||||||
|
const { data } = await req.json();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const order = await createOrder(data);
|
||||||
|
return response(OPERATION, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
return handleError(OPERATION, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
***************************************
|
||||||
|
* PUT - Update PartyOrder
|
||||||
|
***************************************
|
||||||
|
*/
|
||||||
|
export async function PUT(req: NextRequest) {
|
||||||
|
const { searchParams } = req.nextUrl;
|
||||||
|
const orderId = searchParams.get('orderId');
|
||||||
|
const { data } = await req.json();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!orderId) throw new Error('orderId cannot be null');
|
||||||
|
|
||||||
|
const result = await updateOrder(orderId, data);
|
||||||
|
return response(result, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
return handleError('PartyOrder - Update', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
***************************************
|
||||||
|
* DELETE - Delete PartyOrder
|
||||||
|
***************************************
|
||||||
|
*/
|
||||||
|
export async function DELETE(req: NextRequest) {
|
||||||
|
const { searchParams } = req.nextUrl;
|
||||||
|
const orderId = searchParams.get('orderId');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!orderId) throw new Error('orderId cannot be null');
|
||||||
|
|
||||||
|
await deleteOrder(orderId);
|
||||||
|
return response({ success: true }, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
return handleError('PartyOrder - Delete', error);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,35 @@
|
|||||||
|
import type { NextRequest } from 'next/server';
|
||||||
|
|
||||||
|
import { logger } from 'src/utils/logger';
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
import type { IOrderItem } from '../update/route';
|
||||||
|
|
||||||
|
// import { searchEvents } from 'src/app/services/party-event.service';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** **************************************
|
||||||
|
* GET - Search PartyEvents
|
||||||
|
*************************************** */
|
||||||
|
export async function GET(req: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { searchParams } = req.nextUrl;
|
||||||
|
const query = searchParams.get('query')?.trim().toLowerCase();
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
return response({ results: [] }, STATUS.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
const results: IOrderItem[] = [];
|
||||||
|
// TODO: search party event not implemented
|
||||||
|
console.log('search party event not implemented');
|
||||||
|
// const results = await searchEvents(query);
|
||||||
|
|
||||||
|
logger('[PartyEvent] search-results', results?.length);
|
||||||
|
|
||||||
|
return response({ results }, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
return handleError('PartyEvent - Get search', error);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,24 @@
|
|||||||
|
###
|
||||||
|
|
||||||
|
# Search party events by title
|
||||||
|
GET http://localhost:7272/api/party-event/search?query=Music
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# Search party events by location
|
||||||
|
GET http://localhost:7272/api/party-event/search?query=Central+Park
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# Search party events by tag
|
||||||
|
GET http://localhost:7272/api/party-event/search?query=Festival
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# Combined search with multiple parameters
|
||||||
|
GET http://localhost:7272/api/party-event/search?query=Summer&location=Hong+Kong&category=Music
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# No results expected
|
||||||
|
GET http://localhost:7272/api/party-event/search?query=zzzzzz
|
@@ -0,0 +1,51 @@
|
|||||||
|
// src/app/api/party-order/update/route.ts
|
||||||
|
//
|
||||||
|
// PURPOSE:
|
||||||
|
// Update party order in db by id
|
||||||
|
//
|
||||||
|
// RULES:
|
||||||
|
// T.B.A.
|
||||||
|
|
||||||
|
import type { NextRequest } from 'next/server';
|
||||||
|
|
||||||
|
import { STATUS, response, handleError } from 'src/utils/response';
|
||||||
|
|
||||||
|
import { updateOrder } from 'src/app/services/party-order.service';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** **************************************
|
||||||
|
* PUT - Update PartyOrder
|
||||||
|
*************************************** */
|
||||||
|
export async function PUT(req: NextRequest) {
|
||||||
|
const { orderData } = await req.json();
|
||||||
|
const { id } = orderData;
|
||||||
|
|
||||||
|
if (!id) return response({ message: 'id not found' }, STATUS.ERROR);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await updateOrder(id, orderData);
|
||||||
|
|
||||||
|
return response({ result }, STATUS.OK);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating order:', { orderData });
|
||||||
|
return handleError('PartyOrder - Update', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IOrderItem = {
|
||||||
|
id: string;
|
||||||
|
eventId: string;
|
||||||
|
userId: string;
|
||||||
|
status: string;
|
||||||
|
paymentStatus: string;
|
||||||
|
totalAmount: number;
|
||||||
|
items: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
quantity: number;
|
||||||
|
price: number;
|
||||||
|
}[];
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
};
|
@@ -0,0 +1,51 @@
|
|||||||
|
###
|
||||||
|
|
||||||
|
PUT http://localhost:7272/api/party-order/update
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"orderData": {
|
||||||
|
"id":"e99f09a7-dd88-49d5-b1c8-1daf80c2d7b02",
|
||||||
|
"taxes": 10.50,
|
||||||
|
"status": "completed",
|
||||||
|
"shipping": 5.00,
|
||||||
|
"discount": 20.00,
|
||||||
|
"subtotal": 290.00,
|
||||||
|
"orderNumber": "ORD-2023-001",
|
||||||
|
"totalAmount": 300.00,
|
||||||
|
"totalQuantity": 2,
|
||||||
|
"history": {
|
||||||
|
"payment": "2023-01-01",
|
||||||
|
"status_changes": [
|
||||||
|
"pending",
|
||||||
|
"paid"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"method": "credit_card",
|
||||||
|
"card_last4": "4321"
|
||||||
|
},
|
||||||
|
"customer": {
|
||||||
|
"name": "John Doe",
|
||||||
|
"email": "john@example.com"
|
||||||
|
},
|
||||||
|
"delivery": {
|
||||||
|
"method": "express",
|
||||||
|
"tracking_number": "TRK123456"
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "ticket_001",
|
||||||
|
"name": "General Admission",
|
||||||
|
"quantity": 2,
|
||||||
|
"price": 150.00,
|
||||||
|
"status": "used"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"shippingAddress": {
|
||||||
|
"street": "123 Main St",
|
||||||
|
"city": "New York",
|
||||||
|
"zip": "10001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,13 @@
|
|||||||
with knowledge in schema.prisma file,
|
Hi,
|
||||||
please refer the below helloworld example `helloworld.service.ts`
|
|
||||||
and create `user.service.ts` to cover user record
|
|
||||||
|
|
||||||
thanks
|
i copied from
|
||||||
|
`03_source/cms_backend/src/app/services/party-event.service.ts`
|
||||||
|
to
|
||||||
|
`03_source/cms_backend/src/app/services/party-order.service.ts`
|
||||||
|
|
||||||
`/home/logic/_wsl_workspace/001_github_ws/HKSingleParty-ws/HKSingleParty/03_source/cms_backend/src/app/services/helloworld.service.ts`
|
with knowledge in `schema.prisma` file, and reference to the sibling files in same folder
|
||||||
|
|
||||||
|
i want you to update `party-order.service.ts` content to handle party order (the purchase order of the party)
|
||||||
|
please use the model `PartyOrderItem` to handle it.
|
||||||
|
|
||||||
|
thanks.
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
// src/app/services/party-order.service.ts
|
||||||
|
//
|
||||||
|
// PURPOSE:
|
||||||
|
// - Service for handling PartyOrderItem Record
|
||||||
|
//
|
||||||
|
|
||||||
|
import type { PartyOrderItem } from '@prisma/client';
|
||||||
|
|
||||||
|
import prisma from '../lib/prisma';
|
||||||
|
|
||||||
|
type CreateOrder = {
|
||||||
|
status: string;
|
||||||
|
taxes: number;
|
||||||
|
shipping: number;
|
||||||
|
discount: number;
|
||||||
|
items: any[];
|
||||||
|
customer: any;
|
||||||
|
payment: any;
|
||||||
|
delivery: any;
|
||||||
|
shippingAddress: any;
|
||||||
|
billingAddress: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UpdateOrder = {
|
||||||
|
status?: string;
|
||||||
|
taxes?: number;
|
||||||
|
shipping?: number;
|
||||||
|
discount?: number;
|
||||||
|
items?: any[];
|
||||||
|
customer?: any;
|
||||||
|
payment?: any;
|
||||||
|
delivery?: any;
|
||||||
|
shippingAddress?: any;
|
||||||
|
billingAddress?: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function listPartyOrders(): Promise<PartyOrderItem[]> {
|
||||||
|
return prisma.partyOrderItem.findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPartyOrder(partyOrderId: string): Promise<PartyOrderItem | null> {
|
||||||
|
return prisma.partyOrderItem.findUnique({
|
||||||
|
where: { id: partyOrderId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createOrder(orderData: any) {
|
||||||
|
return prisma.partyOrderItem.create({
|
||||||
|
data: orderData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateOrder(orderId: string, updateData: UpdateOrder) {
|
||||||
|
return prisma.partyOrderItem.update({
|
||||||
|
where: { id: orderId },
|
||||||
|
data: updateData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteOrder(orderId: string) {
|
||||||
|
return prisma.partyOrderItem.delete({
|
||||||
|
where: { id: orderId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getPartyOrder as getOrder, createOrder, updateOrder, deleteOrder, listPartyOrders, type CreateOrder, type UpdateOrder };
|
Reference in New Issue
Block a user