Chapter 11: Data Importer & Exporter — 11.8 Virtual Stock Importer
Use the Virtual Stock Importer to set daily quantity limits for many products at once. If you prepare fresh items each day and want them to show "sold out" when they run out, set those limits here in bulk.
When to use this: When you need to update virtual stock allocation for multiple products across outlets using a spreadsheet.

Virtual stock allows a product's stock level to be automatically calculated from its component items, rather than tracked independently. This is useful for gift sets, bundles, combo meals, and any product that is assembled from individually-stocked components. This importer lets you set up these relationships in bulk.
Step 1: Export Template → Download blank template with column headers
Step 2: Fill Data → Enter parent product codes and component mappings
Step 3: Import → Upload the completed file
Step 4: Review → Check import history for success/error status| Element | Type | Function |
|---|---|---|
| Export Template | Button | Downloads a blank template file |
| Import | Button | Opens file picker for the completed template |
| Import History | Data Grid | Shows past import batches with results |
| Column | Required | Description |
|---|---|---|
| ItemNo | ✅ Yes | The parent/virtual product's item number |
| ComponentItemNo | ✅ Yes | The component item that contributes to the virtual stock calculation |
| Quantity | ✅ Yes | How many units of the component are consumed per unit of the parent |
| ItemNo | ComponentItemNo | Quantity |
|---|---|---|
| GIFTSET-001 | PERFUME-A | 1 |
| GIFTSET-001 | LOTION-B | 1 |
| GIFTSET-001 | SOAP-C | 2 |
| COMBO-LUNCH | BURGER-001 | 1 |
| COMBO-LUNCH | FRIES-001 | 1 |
| COMBO-LUNCH | DRINK-001 | 1 |
The parent product's available stock is calculated as the minimum of (Component Stock ÷ Quantity) across all components:
GIFTSET-001 components:
PERFUME-A: 50 in stock ÷ 1 = 50 possible
LOTION-B: 30 in stock ÷ 1 = 30 possible
SOAP-C: 80 in stock ÷ 2 = 40 possible
Virtual stock of GIFTSET-001 = MIN(50, 30, 40) = 30 sets available| Component | Stock On Hand | Qty per Parent | Possible Parent Units |
|---|---|---|---|
| PERFUME-A | 50 | 1 | 50 |
| LOTION-B | 30 | 1 | 30 (limiting factor) |
| SOAP-C | 80 | 2 | 40 |
| Virtual Stock | 30 |
[!NOTE] The virtual stock level automatically updates whenever any component's stock level changes (via stock-in, stock-out, sale, or transfer). No manual recalculation is needed.
| Validation | Error If... |
|---|---|
| Parent Exists | ItemNo does not match any product → "Item Not Found" |
| Component Exists | ComponentItemNo does not match any product → "Component Not Found" |
| Quantity Valid | Quantity is zero, negative, or non-numeric → "Invalid Quantity" |
| No Self-Reference | ItemNo equals ComponentItemNo → "Cannot link item to itself" |
| No Circular Reference | Component is itself a virtual product that references the parent → "Circular Reference Detected" |
| Column | Description |
|---|---|
| Import Date | When the import was processed |
| File Name | Uploaded file name |
| Total Rows | Number of rows in the file |
| Success | Rows imported successfully |
| Failed | Rows that failed validation |
| Download Log | Error details for failed rows |
| Feature | Virtual Stock (this page) | Bundle Setup (Section 2.5) | Material Importer (Section 11.6) |
|---|---|---|---|
| Purpose | Auto-calculate parent stock from components | Sell multiple items as a package with a combined price | Track raw material consumption for costing |
| Stock Impact on Sale | Deducts each component's stock individually | Deducts each bundle item's stock individually | Deducts raw material stock |
| Stock Tracking | Parent has NO independent stock — always calculated | Each item tracked independently | Material tracked independently |
| Use Case | Gift sets, combos where parent has no own inventory | Multi-item promotions with a combined price | F&B recipe ingredients |
Scenario: A cosmetics retailer sells a "Holiday Gift Box" that contains 1 perfume, 1 body lotion, and 2 soaps — all products that are also sold individually. The gift box doesn't have its own inventory; it's assembled on demand from existing stock.
Setup:


| ItemNo | ComponentItemNo | Quantity |
|---|---|---|
| GIFTBOX-HOLIDAY | PERFUME-ROSE | 1 |
| GIFTBOX-HOLIDAY | LOTION-VANILLA | 1 |
| GIFTBOX-HOLIDAY | SOAP-LAVENDER | 2 |
5. The system now calculates: if there are 50 perfumes, 30 lotions, and 80 soaps → Gift Box stock = 30 (limited by lotion).
6. Selling one Gift Box at POS deducts: 1 perfume + 1 lotion + 2 soaps.
[!TIP] Use Virtual Stock alongside the Virtual Stock Setup page (Section 2.12) for individual item configuration. The importer is ideal for bulk setup (50+ virtual products), while the setup page is better for configuring one or two products at a time.
[!WARNING] Virtual stock products should not have their own stock-in operations. Since their stock is calculated from components, doing a stock-in on the virtual product itself will create a discrepancy between the calculated virtual stock and the actual stock-in records.
| Role | View | Create | Edit | Delete |
|---|---|---|---|---|
| Admin | Yes | Yes | Yes | Yes |
| Supervisor | Yes | Yes | Yes | No |
| Cashier | No backend access | — | — | — |
[!NOTE] Exact permissions depend on the Privileges Setup configured for each role. Contact your administrator if you cannot access this page.
Expected Result: Changes are saved successfully and reflected across the system after the next POS sync.
Expected Result: Virtual stock balances are updated for the specified outlets. Changes sync to POS on the next data refresh.
Q: What file format should I use for import? A: Use .xlsx (Excel) format. Download the blank template from the importer page to ensure correct column structure.
Q: Can I undo an import? A: No. Imports cannot be automatically reversed. You would need to manually correct or delete the imported records.
Q: Why does my import show validation errors? A: Check the error details for each row. Common issues include: missing required fields, duplicate codes, invalid date formats, or referencing categories/departments that don't exist yet.
| Issue | Possible Cause | Solution |
|---|---|---|
| Upload fails with error | File format is not .xlsx or file is corrupted | Download a fresh template, re-enter data, and try again |
| Validation errors on rows | Missing required fields or invalid data format | Check the error details column for specific row issues |
| "Duplicate record" warning | Data already exists in the system | Check if the record exists and decide whether to update or skip |
| Import shows 0 records processed | File is empty or wrong template version | Verify the file has data rows and uses the latest template |
| Error 404 on upload | File too large or server timeout | Split the file into smaller batches (max 500 rows recommended) |
| Data imported but not visible | Filters hiding the new records | Clear all filters and search for the imported records |
[!NOTE] The following items may vary depending on your system version and configuration:
- Exact permission settings depend on your Privileges Setup configuration
- Sync timing to POS terminals depends on network conditions and sync schedule
- Some features may require additional licensing or module activation
- Field behavior may differ between EQuip versions
If you encounter behavior not described in this manual, contact your system administrator or EQuip support team.
| Field | Required | Description |
|---|---|---|
| Name / Title | Yes | The display name for this record |
| Status / Active | — | Whether this record is active in the system |
| Created Date | Auto | System-generated creation timestamp |
| Modified Date | Auto | System-generated last modification timestamp |
[!NOTE] Additional fields specific to this page are documented in the sections above. The table above shows common fields present across most pages.