Conversation
This is to estimate prices for warehouse. Adds POST /api/shipping-rates endpoint that allows ambassadors to get Canada Post shipping rate quotes by providing destination address, package type (envelope/box), dimensions (inches), and weight (grams).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ctions CI pipeline
…ubble packet with 0.5in thickness
- Warehouse: stripped admin controls from items/orders pages, now read-only for ambassadors and admins - Warehouse-Backend: new admin-only route with full CRUD for items, orders, categories, and tags
9505.10.2500 -> 9505.10.25.00 (proper dotted format per Canada Post schema)
- address-line-1/2: 44 chars, with overflow from line-1 into line-2 - name: 44 chars, city: 40 chars, prov-state: 20 chars, phone: 25 chars - sku: 15 chars, customs-description: 45 chars
…e versa) INT.TP (Tracked Packet) isn't available for all countries (e.g. CZ). Now automatically retries with Xpresspost International as fallback.
Adds resolveStateCode() for US states and CA provinces (e.g. California -> CA). Applied when creating orders from CSV batches and calculating shipping rates.
- Resolve full state names (e.g. California -> CA) in createShipment XML so existing orders with full names in DB are handled - Only fall back to INT.XP when CP_CONTRACT_ID is set (it requires a contract) - Include error details in 502 response
…shipments Countries like CZ and EG aren't supported by INT.TP. When Canada Post fails for non-CA destinations, automatically try Chit Chats if configured.
- Add INT.SP.AIR, INT.IP, INT.IP.SURF as fallbacks for international shipments - Stop forcing INT.SP.AIR/INT.SP.SURF to INT.TP when no contract - Add International Parcel Air/Surface service code mappings
…hipping rates, add items to rate schema
|
P.S. DO NOT MERGE YET, I NEED TO ADD ENV VARS. |
# Conflicts: # .github/workflows/ci.yml # resolution-frontend/Dockerfile # resolution-frontend/drizzle/meta/0002_snapshot.json # resolution-frontend/drizzle/meta/_journal.json # resolution-frontend/package-lock.json # resolution-frontend/package.json # resolution-frontend/src/lib/server/db/schema.ts # resolution-frontend/src/lib/server/validation/schemas.test.ts # resolution-frontend/src/lib/server/validation/schemas.ts # resolution-frontend/src/routes/app/+page.svelte # resolution-frontend/src/routes/app/admin/+page.svelte
- Add requireAuth() to /api/qz/sign and /api/qz/cert so only authenticated users can sign data or fetch the certificate. - Add admin/ambassador role check to /api/fulfillment/get-label so arbitrary authenticated users cannot create shipments or generate shipping labels.
thesleepyniko
left a comment
There was a problem hiding this comment.
good lord. changes requested, please also get a review from like amp using the code review tool for all files here, ty
There was a problem hiding this comment.
why are we including these files in the frontend? let's make sure this isn't going into prod
There was a problem hiding this comment.
hey are we sure this needs to be merged? if you need to remove admin shouldn't you be going through admin dash?
| <form method="POST" action="?/deleteTemplate" use:enhance> | ||
| <input type="hidden" name="templateId" value={template.id} /> | ||
| <button type="submit" class="delete-btn">Delete</button> | ||
| </form> |
There was a problem hiding this comment.
confirmation dialog here asw
| createOrder: async ({ request, locals }) => { | ||
| const user = locals.user; | ||
| if (!user) { | ||
| return fail(401, { error: 'Not logged in' }); | ||
| } |
There was a problem hiding this comment.
check if user is ambassador or admin please
| const [order] = await db.insert(warehouseOrder).values({ | ||
| createdById: user.id, | ||
| firstName, | ||
| lastName, | ||
| email, | ||
| phone: phone || null, | ||
| addressLine1, | ||
| addressLine2: addressLine2 || null, | ||
| city, | ||
| stateProvince, | ||
| postalCode: postalCode || null, | ||
| country, | ||
| notes: notes || null, | ||
| status: 'APPROVED', | ||
| estimatedShippingCents: estimatedShippingCents ? parseInt(estimatedShippingCents) : null, | ||
| estimatedServiceName: estimatedServiceName || null, | ||
| estimatedServiceCode: estimatedServiceCode || null | ||
| }).returning({ id: warehouseOrder.id }); | ||
|
|
||
| await Promise.all( | ||
| items.map((item) => | ||
| db.insert(warehouseOrderItem).values({ | ||
| orderId: order.id, | ||
| warehouseItemId: item.warehouseItemId, | ||
| quantity: item.quantity, | ||
| sizingChoice: item.sizingChoice || null | ||
| }) | ||
| ) | ||
| ); | ||
|
|
||
| for (const item of items) { | ||
| const result = await db.update(warehouseItem) | ||
| .set({ quantity: sql`${warehouseItem.quantity} - ${item.quantity}` }) | ||
| .where(and(eq(warehouseItem.id, item.warehouseItemId), gte(warehouseItem.quantity, item.quantity))); | ||
| if (result.rowCount === 0) { | ||
| return fail(409, { error: `Insufficient stock (concurrent update). Please try again.` }); | ||
| } | ||
| } |
There was a problem hiding this comment.
all of this should be one transaction to prevent a case where an order is placed but stock wasn't deducted
| if (!user.isAdmin) { | ||
| const ambassadorPathways = await db | ||
| .select({ pathway: ambassadorPathway.pathway }) | ||
| .from(ambassadorPathway) | ||
| .where(eq(ambassadorPathway.userId, user.id)) | ||
| .limit(1); | ||
|
|
||
| if (ambassadorPathways.length > 0) { | ||
| const orgId = getOrgIdForPathway(ambassadorPathways[0].pathway); | ||
| if (orgId) { | ||
| let itemsTotalCents = 0; | ||
| for (const item of items) { | ||
| const stock = stockMap.get(item.warehouseItemId); | ||
| if (stock) { | ||
| itemsTotalCents += stock.costCents * item.quantity; | ||
| } | ||
| } | ||
| const shippingCents = estimatedShippingCents ? parseInt(estimatedShippingCents) : 0; | ||
| const totalCents = itemsTotalCents + shippingCents; | ||
|
|
||
| if (totalCents > 0) { | ||
| await createHcbTransfer( | ||
| orgId, | ||
| totalCents, | ||
| `Warehouse order #${order.id} by ${firstName} ${lastName}` | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
order may ship for free should the hcb transfer fail
| with: { | ||
| createdBy: true, |
There was a problem hiding this comment.
full user objects being leaked here
thesleepyniko
left a comment
There was a problem hiding this comment.
good lord. changes requested, please also get a review from like amp using the code review tool for all files here, ty
|
also
|
Summary
Adds a complete warehouse management system to Resolution, allowing ambassadors to place orders for physical inventory and admins to fulfill them with integrated multi-carrier shipping label generation.
Features
Warehouse Storefront (Ambassadors - /app/warehouse)
Browse inventory items grouped by category
Multi-step order wizard with address entry, item selection, and real-time shipping rate comparison
Order templates for quick reordering
Batch ordering via CSV upload with auto-field-mapping and a linked Google Sheets template
Tag input with chips and autocomplete for order filtering
Orders and batches scoped to the logged-in user
Warehouse Backend (Admins - /app/warehouse-backend)
Full CRUD for inventory categories and items (photo uploads via Hack Club CDN, dimensions, HS codes, sizing options)
Inventory tracking with automatic quantity subtraction on order placement (prevents negative stock)
Fulfillment panel with label generation, printing, and reprint support
Shipping Integration
Canada Post — contract and non-contract shipment support, state/province → 2-letter code resolution, country name → ISO code mapping, 8.5×11 → 4×6 label cropping
Chit Chats — rate quoting and shipment creation with HTS codes and manufacturer details; automatic fallback when Canada Post fails internationally
Theseus — lettermail label support
Zonos — landed cost integration for US-bound shipments
Cheapest-rate auto-selection across all carriers for batch shipping
Flat package type with envelope size snapping (4×6 / 6×9)
Printing
QZ Tray integration for direct thermal label printing (4×6)
Combined label + packing slip print button
Reprint support for previously generated labels
Billing
HCB (Hack Club Bank) billing integration for warehouse orders
Infrastructure
4 new Drizzle migrations (orders, templates/batches, label tracking, HS codes)
drizzle-kit push at container startup for auto-migrations
entrypoint.sh for container orchestration
removeAdmin.mjs CLI script
Staging mode to bypass OAuth for local/staging testing
Body size limit increased to 10MB for image uploads
UI
Phantom Sans font and clean white UI on warehouse, admin, and ambassador pages
Shipping cost estimate disclaimers on order and batch pages
Modified
Extended DB schema with warehouse orders, templates, batches, label/tracking fields
Updated admin page with warehouse backend link and inventory management
Updated validation schemas and tests for new order/item types
CI triggers on warehouse-dev branch
P.S. DO NOT MERGE YET, I NEED TO ADD ENV VARS.