
Vendor Management
- 148 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Implement vendor onboarding, catalog sync, purchase orders, commission rules, and payout tracking for marketplace or multi-supplier ecommerce operations.
About
vendor-management skill from finsilabs/awesome-ecommerce-skills guides marketplace supplier operations: vendor profiles, product ingestion, PO lifecycle, commission calculations, performance metrics, and payout reconciliation integrated with ecommerce admin and order systems.
- Vendor onboarding flows
- Catalog and inventory sync
- Purchase order tracking
- Commission and fee rules
- Payout reconciliation
Vendor Management by the numbers
- 148 all-time installs (skills.sh)
- Ranked #2,545 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill vendor-managementAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 148 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Implement vendor onboarding, catalog sync, purchase orders, commission rules, and payout tracking for marketplace or multi-supplier ecommerce operations.
Files
Vendor Management
Overview
Vendor management covers creating and sending purchase orders to suppliers, tracking goods receipts, running vendor performance scorecards (on-time rate, fill rate, defect rate), and maintaining a supplier portal where vendors can acknowledge POs and provide tracking numbers. For most merchants, QuickBooks/Xero handles POs and vendor tracking, while a supplier portal can be as simple as an email-based workflow for smaller operations.
When to Use This Skill
- When managing 5+ suppliers and need a centralized system instead of email-based coordination
- When your merchandising team manually creates purchase orders in spreadsheets and needs automation
- When onboarding new dropship suppliers and need a structured integration flow
- When preparing quarterly business reviews with suppliers and need performance metrics
- When building a multi-vendor marketplace where each seller needs their own dashboard
Core Instructions
Step 1: Determine your platform and choose the right vendor management tool
| Store Stage | Recommended Tool | Why |
|---|---|---|
| Small (< $1M revenue) | QuickBooks Online or Xero + email-based POs | QuickBooks handles POs, vendor payments, and basic receipt tracking; most small merchants don't need a dedicated vendor portal |
| Mid-market ($1M–$20M) | DEAR Inventory (now Cin7 Core) or Unleashed | Both handle POs, goods receipts, and vendor scorecards with Shopify/WooCommerce/BigCommerce integrations |
| Enterprise | NetSuite or Coupa | Full procurement suite with approval workflows, supplier portals, and compliance tracking |
| Dropshipping focus | DSers, AutoDS, or Spocket | See @dropshipping-integration skill for supplier-specific dropshipping tools |
| Custom | Build a PO system + supplier portal | For unique workflows that existing tools don't support |
Step 2: Connect your e-commerce platform to your vendor management system
Shopify
Using Cin7 Core (formerly DEAR Inventory): 1. Install the Cin7 Core connector from the Shopify App Store or via the Cin7 Core integration settings 2. Cin7 Core syncs Shopify products and inventory — your Shopify stock levels reflect what Cin7 shows as "on hand" 3. Create purchase orders in Cin7 Core → Purchase → Add Purchase 4. When goods are received in Cin7 (mark as Received), Shopify inventory updates automatically
Using QuickBooks Online for POs: 1. Connect QuickBooks to Shopify via the QuickBooks Online app or A2X connector 2. Create POs in QuickBooks Online → Expenses → Purchase Orders 3. When goods are received: in QuickBooks, go to the PO and click "Receive" to record the goods receipt 4. Manually update Shopify inventory after receiving (or use Cin7 Core which does this automatically)
WooCommerce
Using ATUM Inventory Management (PO module): 1. Install ATUM Inventory Management from WordPress.org (premium version for PO features) 2. Go to ATUM → Purchase Orders → Add PO 3. Select supplier, add products, set expected delivery date 4. ATUM emails the PO to the supplier automatically 5. When goods arrive: mark the PO as received in ATUM → WooCommerce inventory updates automatically
Using Cin7 Core: 1. Connect Cin7 Core to WooCommerce via their integration (Cin7 Core → Integrations → WooCommerce) 2. Manage all POs and vendor relationships in Cin7 Core; inventory syncs back to WooCommerce
BigCommerce
Using Unleashed: 1. Install the Unleashed connector from the BigCommerce App Marketplace 2. Create purchase orders in Unleashed → Purchases → New Purchase Order 3. Unleashed syncs inventory back to BigCommerce when POs are received
Using Cin7 Core: 1. Connect via BigCommerce API integration in Cin7 Core settings 2. Same workflow as Shopify/WooCommerce
Step 3: Create and send purchase orders to suppliers
A good PO includes: your PO number, item descriptions with your SKU and the supplier's SKU, quantities, unit costs, expected delivery date, and delivery address.
In QuickBooks Online
1. Go to Expenses → Vendors → [Vendor] → click New Transaction → Purchase Order 2. Fill in: vendor, PO date, expected ship date, items with quantities and unit costs 3. Click Save and Send to email the PO directly to the vendor from QuickBooks 4. Track the PO status in Expenses → Purchase Orders — open POs show as "Open", received as "Closed"
In Cin7 Core / ATUM
1. Navigate to Purchase → New Purchase Order 2. Select the supplier; the system pre-fills the supplier's products from your supplier catalog 3. Adjust quantities based on your reorder quantities (see @demand-forecasting) 4. Set the expected delivery date: your supplier's lead time + today's date 5. Send the PO via the built-in email workflow — the PO PDF is attached to the email
Using a simple email template (for merchants not using a PO system yet)
Subject: Purchase Order PO-202603-001
Dear [Supplier Contact],
Please find our purchase order details below:
PO Number: PO-202603-001
Order Date: March 12, 2026
Expected Delivery: March 26, 2026
Items:
| SKU | Description | Qty | Unit Cost | Total |
|-----|-------------|-----|-----------|-------|
| YS-1001 | Cotton T-Shirt, White, S | 100 | $8.50 | $850.00 |
| YS-1002 | Cotton T-Shirt, White, M | 150 | $8.50 | $1,275.00 |
Total: $2,125.00
Payment Terms: Net 30
Please confirm receipt of this order and your expected ship date.
Ship to:
[Your warehouse address]Step 4: Set up a supplier portal for PO acknowledgment
For suppliers who work via email, a simple acknowledgment email workflow is sufficient. For higher-volume supplier relationships, a portal improves visibility.
Simple email-based workflow: 1. Send PO via email with a reply-by date (2 business days) asking the supplier to confirm: PO number, items, quantities, and expected ship date 2. When the supplier replies, update the PO status in your system to "Acknowledged" 3. If the supplier can't fulfill the full quantity, get a partial commitment in writing
ATUM Supplier Portal (WooCommerce): 1. ATUM Premium includes a supplier-facing portal where suppliers receive POs, acknowledge them, and enter tracking numbers 2. Go to ATUM → Suppliers → [Supplier] → configure portal access credentials
Cin7 Core Supplier Portal: 1. Cin7 Core includes a supplier portal where vendors can view POs, confirm delivery dates, and upload shipping documents 2. Invite suppliers in Cin7 Core → Settings → Suppliers → Invite to Portal
Step 5: Track goods receipt and update inventory
When a shipment arrives from a supplier:
1. Match the packing list to the purchase order — check every line item's quantity 2. Identify any discrepancies:
- Short shipment: supplier sent fewer units than ordered → update PO with received qty, leave PO "open" for the balance
- Damaged goods: record separately; do not put damaged inventory into your sellable stock
- Wrong items: contact supplier immediately with photos for credit memo
In QuickBooks:
- Open the PO → click "Receive Items" → enter actual received quantities
- QuickBooks creates a bill for the received quantity automatically
In Cin7 Core / ATUM:
- Navigate to the PO → click "Receive Stock" → enter quantities received per line
- Inventory updates automatically in Shopify/WooCommerce/BigCommerce
Step 6: Calculate and review vendor performance scorecards
Run vendor scorecards quarterly to identify underperforming suppliers and support negotiation.
Key metrics:
| Metric | Definition | Target |
|---|---|---|
| On-time delivery rate | % of POs where actual receipt date ≤ expected delivery date | > 90% |
| Fill rate | Total units received / total units ordered across all POs | > 95% |
| Defect rate | Damaged/incorrect units received / total units received | < 2% |
| Lead time accuracy | Actual lead time vs. quoted lead time | ± 2 days |
Calculate from your PO system:
In QuickBooks, export PO data to a spreadsheet and compute these metrics. In Cin7 Core and ATUM, built-in vendor reports provide these metrics automatically.
Custom / Headless — vendor scorecard calculation
async function calculateVendorScorecard(params: {
vendorId: string;
periodDays: number;
}): Promise<{
onTimeRatePct: number;
fillRatePct: number;
defectRatePct: number;
overallScore: number; // 0–100
}> {
const since = new Date(Date.now() - params.periodDays * 86400000);
const pos = await db.purchaseOrders.findAll({
vendor_id: params.vendorId,
status: { in: ['received', 'partial'] },
created_at: { gte: since },
});
if (pos.length === 0) return { onTimeRatePct: 0, fillRatePct: 0, defectRatePct: 0, overallScore: 0 };
// On-time: PO received on or before expected delivery date
const onTimeCount = pos.filter(po => po.received_at && po.received_at <= new Date(`${po.expected_delivery}T23:59:59Z`)).length;
// Fill rate: total received / total ordered
const allLines = await db.poLines.findByPoIds(pos.map(p => p.id));
const totalOrdered = allLines.reduce((s, l) => s + l.quantity_ordered, 0);
const totalReceived = allLines.reduce((s, l) => s + l.quantity_received, 0);
// Defect rate: damaged units / total received
const totalDamaged = await db.damagedReceipts.sumByVendorAndPeriod(params.vendorId, since);
const onTimeRatePct = (onTimeCount / pos.length) * 100;
const fillRatePct = totalOrdered > 0 ? (totalReceived / totalOrdered) * 100 : 0;
const defectRatePct = totalReceived > 0 ? (totalDamaged / totalReceived) * 100 : 0;
// Weighted score: on-time 40%, fill rate 40%, defect-free 20%
const overallScore = Math.round(
(onTimeRatePct * 0.4) + (fillRatePct * 0.4) + ((100 - defectRatePct) * 0.2)
);
return { onTimeRatePct, fillRatePct, defectRatePct, overallScore };
}Best Practices
- Use your accounting software (QuickBooks, Xero) for POs if you're under $1M — it integrates AP and inventory receiving in one tool; you don't need a separate vendor portal at this stage
- Set expected delivery dates conservatively — add the vendor's quoted lead time plus a 2-day buffer; this improves on-time metrics without changing actual performance
- Track partial receipts carefully — many POs arrive in multiple shipments; record the received quantity per line and keep the PO open until fully received
- Record defects at the dock, not later — damaged goods must be logged at receiving time with photos; retrospective claims are harder to substantiate with suppliers
- Share scorecards with suppliers quarterly — suppliers who see their metrics improve; use the data in pricing negotiations ("your fill rate dropped to 88% last quarter")
Common Pitfalls
| Problem | Solution |
|---|---|
| PO total doesn't match the supplier's invoice | Store unit costs at the PO line level and never update them retroactively; price discrepancies become AP exceptions flagged for review |
| Supplier ships to the wrong address | Include the warehouse address on every PO and in the portal confirmation screen; verify the ship-to address has been acknowledged |
| Inventory incremented before damaged goods are removed from the count | Only increment inventory for receipts with condition = 'good'; damaged goods go to a quarantine count, not sellable stock |
| Scorecard shows high on-time rate but stock still runs out | On-time rate measures delivery vs. expected date, not vs. actual demand need date; also track "stockout events attributed to late delivery" as a separate metric |
Related Skills
- @dropshipping-integration
- @order-management-system
- @multi-channel-selling
- @demand-forecasting
- @accounts-payable-management
{
"context": "Tests whether the agent correctly implements partial receipt tracking with damaged goods quarantine and a vendor scorecard with the correct metrics, period, and weighted formula.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Partial status tracking",
"max_score": 10,
"description": "The receiveGoodsAgainstPO function sets PO status to 'partial' when not all line quantities have been fully received, and 'received' when all lines are complete"
},
{
"name": "Per-line quantity tracking",
"max_score": 8,
"description": "The function updates quantity_received on individual po_lines (not just the PO header), accumulating received quantities across multiple deliveries"
},
{
"name": "Good condition inventory update",
"max_score": 10,
"description": "Inventory is only incremented for items received in 'good' condition — damaged items do NOT cause an inventory increment"
},
{
"name": "Damaged goods quarantine",
"max_score": 10,
"description": "Damaged items are inserted into a separate table (damagedGoods, quarantine, or equivalent) rather than being discarded or merged with good inventory"
},
{
"name": "Receipt in transaction",
"max_score": 8,
"description": "The receiveGoodsAgainstPO function wraps all database updates (line updates, inventory, damaged goods, status) in a single database transaction"
},
{
"name": "90-day default period",
"max_score": 8,
"description": "The generateVendorScorecard function defaults to a 90-day lookback period when periodDays is not specified"
},
{
"name": "On-time rate formula",
"max_score": 8,
"description": "On-time rate is calculated as (number of POs received on or before expected_delivery) / (total POs in period), expressed as a ratio 0–1"
},
{
"name": "Fill rate formula",
"max_score": 8,
"description": "Fill rate is calculated as total quantity_received / total quantity_ordered across all lines in the period, expressed as a ratio 0–1"
},
{
"name": "Defect rate formula",
"max_score": 8,
"description": "Defect rate is calculated as total damaged units / total received units, expressed as a ratio 0–1"
},
{
"name": "Scorecard weights",
"max_score": 12,
"description": "The overall score formula applies weights of 40% to on-time rate, 40% to fill rate, and 20% to (1 - defect rate), scaled to 0–100"
},
{
"name": "Weights documented",
"max_score": 10,
"description": "scorecard_explanation.md explicitly states the formula and the three weights (40/40/20) used to compute the overall score"
}
]
}
Goods Receipt Processing and Vendor Performance Reporting
Problem Description
NorthBay Goods' warehouse team needs a system to log what actually arrives from vendors — both in terms of quantities and quality. This is more complex than it sounds: large orders often arrive in several shipments over multiple days, and some items arrive damaged. The warehouse staff cannot wait until an entire order is complete before updating inventory; they need to update stock levels for each individual delivery as it arrives. At the same time, damaged items must be clearly separated from sellable stock — in a previous system, damaged goods were accidentally added to inventory and sold to customers.
On the reporting side, the operations VP wants a quarterly performance review system for suppliers. She needs an objective, numeric scorecard for each vendor that the procurement team can use in contract renewal negotiations. The scorecard must measure delivery reliability, order completeness, and quality. It should look back over a configurable recent time window and produce a single overall score that can be compared across vendors.
The product team has asked you to implement both pieces: the receiving workflow and the scorecard generation. The receiving workflow must handle both complete and partial deliveries correctly. The scorecard must be computed from actual historical data in the database and follow a defined weighting formula.
Output Specification
Produce a TypeScript file receiving_and_scorecard.ts containing: 1. A receiveGoodsAgainstPO(poId, receipts) function for processing incoming shipments 2. A generateVendorScorecard(vendorId, periodDays?) function returning on-time rate, fill rate, defect rate, and an overall score
Also produce scorecard_explanation.md that explains:
- What each of the three metrics measures and how it is calculated
- How the overall score is derived from the three metrics (include the formula and weights)
- What the default lookback window is, what it represents, and why it was chosen
You may assume the following are already available as imports:
db— a database client with standard query methods- Types for PO lines, purchase orders, and vendor entities
Do not call any external APIs. All data comes from the mock db client.
{
"context": "Tests whether the agent implements the vendor portal using token-based authentication with deep links, correct acknowledgment status guards, buyer notification, ship-to address confirmation, expected delivery buffer, and unit cost immutability.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Token-based portal links",
"max_score": 10,
"description": "The submitPurchaseOrder function generates a portal token and includes it as a URL parameter in the email link (not a persistent password or session cookie approach)"
},
{
"name": "Short-lived token expiry",
"max_score": 8,
"description": "The token generation includes a 7-day expiry (or the design notes describe short-lived tokens with ~7-day lifetime) rather than indefinite validity"
},
{
"name": "One-click deep link",
"max_score": 8,
"description": "The email to the vendor contains an acknowledgeUrl / deep link that goes directly to the specific PO (includes poId) so the vendor can confirm in one click"
},
{
"name": "Ship-to address in email",
"max_score": 8,
"description": "The PO email to the vendor includes the ship-to address in the email body data/template"
},
{
"name": "Address confirmation in portal",
"max_score": 8,
"description": "The portal acknowledgment flow requires the vendor to confirm the ship-to address (either as a required field, a confirm checkbox, or notes to this effect in design_notes.md)"
},
{
"name": "Vendor ownership check",
"max_score": 8,
"description": "The acknowledgment endpoint verifies that the PO belongs to the authenticated vendor (compares po.vendor_id with req.vendor.id or equivalent)"
},
{
"name": "Already-acknowledged guard",
"max_score": 8,
"description": "The acknowledgment endpoint returns an error (HTTP 422 or equivalent) when the PO status is not 'submitted'"
},
{
"name": "Buyer notification",
"max_score": 8,
"description": "The acknowledgment handler sends an email to the buyer after a successful acknowledgment"
},
{
"name": "Delivery date buffer",
"max_score": 10,
"description": "The calculateExpectedDelivery function adds lead_time_days PLUS an additional 2-day buffer (total = lead_time_days + 2)"
},
{
"name": "Unit cost immutability",
"max_score": 8,
"description": "The design_notes.md or code comments explicitly state that unit costs stored at PO creation time must NOT be updated retroactively, and discrepancies are flagged for AP review"
},
{
"name": "PO status update on submit",
"max_score": 8,
"description": "The submitPurchaseOrder function updates the PO status to 'submitted' and records submitted_at timestamp after sending the email"
},
{
"name": "Acknowledgment timestamp",
"max_score": 8,
"description": "The acknowledgment endpoint sets status to 'acknowledged' and records acknowledged_at timestamp"
}
]
}
Vendor Portal: PO Submission and Acknowledgment Flow
Problem Description
NorthBay Goods has finished its database schema and now needs the backend logic for the purchase order workflow. The procurement team submits POs to vendors electronically, and vendors — many of whom are small family businesses with no technical staff — need an easy way to confirm the order. Previous integrations that required vendors to log in and navigate a portal resulted in a 40% non-response rate because low-tech suppliers found it too complicated.
The solution is to email the vendor a link they can click once to confirm the order without any login process. The engineering team must implement: (1) the function that submits a PO by emailing the vendor, and (2) the API endpoint the vendor hits when they click the confirmation link. Security is a concern because vendor portal links will be sent over email — the team must not expose persistent credentials, and must handle the case where a vendor tries to confirm an order that was already confirmed.
The expected delivery date logic is also part of this milestone. When creating a new PO, the system must calculate a realistic delivery date that accounts for each vendor's lead time while building in some cushion for delays. The finance team insists that unit costs recorded at order time must never be changed after the fact — any discrepancy with the eventual invoice is handled by accounts payable, not by editing the PO.
Output Specification
Produce a TypeScript implementation file vendor_portal.ts containing: 1. A submitPurchaseOrder(poId: string) function that emails the vendor and updates PO status 2. A POST endpoint handler for vendor acknowledgment (Express-style or equivalent) 3. A calculateExpectedDelivery(vendor: { lead_time_days: number }, orderDate: Date) helper function
Also produce design_notes.md explaining the security decisions made around portal access and why unit costs are handled a particular way.
You may assume the following are already available as imports:
db— a database client with the methods shown in the examplesemailService— an email service with asend({ to, template, data })methodprocess.env.VENDOR_PORTAL_URL— the portal base URL
Do not use real API keys or credentials. Use placeholder strings where needed.
{
"context": "Tests whether the agent follows the vendor management skill's specific schema design choices: UUID keys, integer cent storage, sequence-based PO numbering, correct status enumerations, and generated columns.",
"type": "weighted_checklist",
"checklist": [
{
"name": "UUID primary keys",
"max_score": 10,
"description": "All three tables (vendors, purchase_orders, po_lines) use UUID as the primary key type with gen_random_uuid() as default"
},
{
"name": "Cents storage",
"max_score": 12,
"description": "Monetary fields (unit_cost, total_cost, or equivalent) are stored as INTEGER (not DECIMAL/NUMERIC/FLOAT), with a comment or note indicating cents"
},
{
"name": "PO sequence exists",
"max_score": 10,
"description": "A PostgreSQL sequence (CREATE SEQUENCE or equivalent) is created for generating purchase order numbers"
},
{
"name": "PO number format",
"max_score": 10,
"description": "The schema or notes describe/implement a PO number format of PO-YYYYMM-NNNN (year+month prefix with zero-padded 4-digit sequence number)"
},
{
"name": "PO number unique constraint",
"max_score": 8,
"description": "The purchase_orders table has a UNIQUE constraint on the po_number column"
},
{
"name": "Vendor status CHECK",
"max_score": 8,
"description": "The vendors table has a status column with a CHECK constraint limiting values to 'active', 'inactive', and 'probation'"
},
{
"name": "PO status CHECK",
"max_score": 10,
"description": "The purchase_orders table has a status column with a CHECK constraint that includes all of: 'draft', 'submitted', 'acknowledged', 'partial', 'received', 'cancelled'"
},
{
"name": "Generated line total",
"max_score": 12,
"description": "The po_lines table includes a computed/generated column for line total (quantity * unit_cost) using GENERATED ALWAYS AS ... STORED syntax"
},
{
"name": "Payment terms values",
"max_score": 8,
"description": "The vendors table includes a payment_terms column with default 'net30' and notes/comment indicating valid values include 'net30', 'net60', and 'prepay'"
},
{
"name": "Partial receipts support",
"max_score": 12,
"description": "The po_lines table includes a quantity_received column (separate from quantity_ordered) to support partial receipt tracking"
}
]
}
Vendor Management Database Setup
Problem Description
A mid-sized e-commerce company called NorthBay Goods is expanding its supplier network from 3 vendors to over 30. Their current process — emailing spreadsheets back and forth with purchase order details — is breaking down: orders get lost, costs are mis-entered, and there's no audit trail. The engineering team has been tasked with building a proper vendor management backend.
The first milestone is setting up the database schema that will power the system. The data model needs to represent suppliers, purchase orders, and individual line items on those orders. The schema should be production-ready: it needs to enforce data integrity through appropriate constraints, handle multiple currencies for international suppliers, track payment terms, and record both what was ordered and what was actually received for each line item.
A key requirement from the finance team is that all monetary amounts must be stored in a way that avoids floating-point rounding errors — the company lost money in a previous system due to decimal precision issues. The operations team also needs a reliable, human-readable order numbering scheme so that phone conversations with suppliers can reference a specific order unambiguously.
Output Specification
Write the SQL migration files to create the database schema for the vendor management system. Produce the following:
schema.sql— a single SQL file containing allCREATE TABLEstatements, constraints, sequences, and indexes needed to set up the schema from scratchschema_notes.md— a brief document explaining the key design decisions made (data types chosen, constraint rationale, numbering approach)
The schema must be valid PostgreSQL syntax. Do not include any INSERT statements or test data.
{
"name": "finsi/vendor-management",
"version": "0.1.0",
"summary": "Vendor portal, purchase orders, dropship routing, and performance scorecards",
"skills": {
"vendor-management": {
"path": "SKILL.md"
}
}
}