# Zhik Forward Order Module

## Overview

The Zhik Forward Order module extends the existing Portal module to enable bulk seasonal ordering for B2B customers (dealers). This module provides functionality for managing ordering periods, CSV pricing uploads, and forward order processing.

## Features

- **Ordering Period Management**: Create and manage forward ordering periods with start/end dates
- **CSV Pricing Upload**: Upload forward order pricing (type 'F') with Trade/Retail extensions via CSV
- **Forward Order Form**: Independent ordering interface at `/forward-order/order` for qualified dealers
- **Category Item Counts**: Headers show product counts (e.g., "OFS900 RANGE [04]")
- **Stock Bypass**: Complete inventory validation bypass - unlimited quantities, no stock impact
- **Custom Pricing**: Forward order prices (type 'F') with Trade/Retail display prices
- **Payment Processing**: Support for prepayment with configurable thresholds
- **Access Control**: Restricted to customers with price class prefix 03 or 04
- **Order Identification**: Orders marked with type 'SF' (Sales Forward) in database
- **Draft Persistence**: localStorage auto-save (shared architecture with Portal)
- **Floating Summary Bar**: Real-time order total with scroll-aware visibility

## Requirements

- Magento 2.4.8-p1 Commerce Edition
- PHP 8.2 or higher
- Zhik_Portal module (required dependency - provides base order functionality)
- Zhik_Myoba module (**CRITICAL dependency** - provides inventory reservation system override)

**⚠️ IMPORTANT**: The stock bypass functionality depends on Zhik_Myoba's preference for `PlaceReservationsForSalesEventInterface`. Without Myoba's override of the core inventory reservation system, the forward order stock bypass will NOT function correctly.

## Installation

### Via Composer (Recommended)

```bash
composer require zhik/module-forward-order
bin/magento module:enable Zhik_ForwardOrder
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
```

### Manual Installation

1. Create the module directory:
   ```bash
   mkdir -p app/code/Zhik/ForwardOrder
   ```

2. Copy module files to the directory

3. Enable the module:
   ```bash
   bin/magento module:enable Zhik_ForwardOrder
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento setup:static-content:deploy -f
   bin/magento cache:flush
   ```

## Configuration

Navigate to **Stores > Configuration > Zhik Extensions > Forward Orders** in the admin panel.

### General Settings
- **Enable Forward Order Module**: Enable/disable the module
- **Forward Order Category**: Select the catalog category for forward order products
- **Customer Price Class Prefixes**: Restricted to price classes starting with 03 or 04 (e.g., 03_DEALER, 04_WHOLESALE)

### Order Processing
- **Enable Prepayment**: Allow prepayment for forward orders
- **Prepayment Threshold**: Order amount requiring prepayment (default: $5000)
- **Force Prepayment**: Require prepayment for all orders
- **Allowed Countries**: Countries allowed for forward ordering

### Payment Settings
- **Enabled Payment Methods**: Available payment methods
- **Payment Surcharge %**: Credit card surcharge (default: 1.5%)
- **Notification Email**: Email for order notifications

## Admin Menu Structure

The module adds the following menu items under **Zhik Extensions**:

- **Forward Orders**
  - Manage Ordering Periods
  - CSV Pricing Upload
  - Configuration

## Key Implementation Details

### Stock Bypass System
Forward orders completely bypass inventory checks and don't affect stock levels:
- **Unlimited Quantities**: Place orders for any quantity, regardless of available stock
- **No Stock Impact**: Orders don't create inventory reservations or reduce stock counts
- **Product Availability**: All products in the forward order catalog are always available

**Why This Matters**: Forward orders are for future seasonal production. The products may not exist in inventory yet, so stock validation would prevent ordering. This bypass allows you to order products that will be manufactured later.

**Critical Dependency**: This functionality requires the Zhik_Myoba module to be installed and enabled. Without it, the stock bypass will not function correctly.

### Order Type
- Forward orders are marked with type 'SF' (Sales Forward) in the system
- This allows them to be tracked separately from regular sales orders
- The 'SF' type ensures the order is processed with forward order rules

### Performance
- First load: 5.74s | Revisit: **462ms** (95% improvement)
- Category counts rendered server-side and cached with block
- Stock bypass eliminates inventory queries for unlimited ordering

### Pricing System
Forward Order prices are managed separately from regular MYOB pricing:
- **Price Source**: Uploaded via CSV in admin (Admin > Forward Orders > CSV Pricing Upload)
- **Price Type**: Type 'F' (Forward Order) - distinct from regular trade pricing
- **Display Prices**: Shows three price points for reference:
  - **RRP** (Retail Price) - Suggested retail price
  - **TRADE** (Trade Price) - Standard dealer price
  - **FORWARD ORDER** (Your Price) - Special forward order pricing
- **Tax Display**: Prices shown both including and excluding tax (where applicable)

**Important**: Forward order prices are completely isolated from regular MYOB price synchronization. They won't be overwritten when MYOB prices are updated.

### Portal vs Forward Order Price Isolation

The pricing systems are completely isolated to prevent price contamination:

| Order Type | Price Types Used | Mechanism |
|------------|------------------|-----------|
| **Portal Orders** | C, P, N (Customer, Promo, Normal) | `TradePrice` observer calls `getMyobPrice()` |
| **Forward Orders** | F (Forward) | `PriceTypePlugin` intercepts and forces F prices |

**How it works:**
1. Both Portal and Forward Order use `Zhik\Myoba\Helper\Data::getMyobPrice()` for pricing
2. Portal's `TradePrice` observer passes default price types: `['C', 'P', 'N']`
3. Forward Order's `PriceTypePlugin` intercepts the call and changes to: `['F']`
4. Detection uses Generic session flag set by Forward Order Submit controller
5. This ensures Forward Orders always get F prices, even when processed through Portal's code path

### Frontend Access
- Customer-facing form: `/forward-order/order`
- Admin CSV upload: Admin > Zhik Extensions > Forward Orders > CSV Pricing Upload

### Customer Account Navigation

**Navigation Link:** "Create Forward Order"
- **Location**: Customer Account sidebar (position 239, between "Create Order" and "Saved Orders")
- **Visibility**: Conditional - only for eligible customers
- **Implementation**: `Plugin/Portal/Block/Account/AddForwardOrderNavigation.php`

**Eligibility Requirements:**
1. Customer logged in
2. Has `myoba_price_class` attribute
3. Price class matches configured prefixes (03*, 04*, etc.)
4. At least one enabled ordering period exists
5. Period date range is active (within start/end dates)
6. Passes customer-specific ID restrictions (if any)

**Technical Details:**
- Plugin hooks: `Zhik\Portal\Block\Account\Navigation::afterUpdateLinks()`
- Eligibility check: `OrderingPeriod::canAccessForwardOrders()`
- Logging: Debug/info logs to system.log with prefix "[Forward Order Nav]"
- Same logic as: Controller access control + Global countdown timer

### Sales Rep Access (Story 1.3.2)

**Navigation Link:** Always visible to sales representatives
- **Location**: Customer Account sidebar (same position as dealer view)
- **Visibility**: Automatically shown for all sales reps, regardless of ordering periods
- **Implementation**: Navigation plugin detects sales rep customer group

**Dealer Selection Interface:**
Sales representatives can place forward orders on behalf of their assigned dealers:

1. **Access the Forward Order page** - Navigate to "Create Forward Order" link
2. **Select a dealer** - Choose from a dropdown of eligible dealers:
   - Only dealers with the correct price class (03*, 04*, etc.) are shown
   - Only dealers with active ordering periods are included
   - Dealers are filtered based on your sales rep level:
     - **Default Rep**: See only your assigned dealers
     - **Super Rep**: See all dealers globally
     - **Regional Rep**: See dealers from your region (same website)
     - **Country-Level Rep**: See dealers from your country
3. **Place orders** - Once a dealer is selected, the forward order form loads with:
   - Dealer-specific forward order pricing
   - Dealer's currency and store configuration
   - Dealer's eligible ordering periods
   - Stock bypass (no inventory limitations)

**Order Tracking:**
- Orders placed by sales reps are marked with: "Placed via sales rep forward order portal by [Your Name]"
- Order customer is the selected dealer (not the sales rep)
- Orders appear in the dealer's account history

**Switching Between Dealers:**
You can change the selected dealer at any time using the dealer selection dropdown. The form will reload with the new dealer's configuration.

## Module Structure

```
app/code/Zhik/ForwardOrder/
├── Api/                    # Service contracts
├── Block/                  # Block classes (independent, not extending Portal)
├── Controller/
│   ├── Adminhtml/         # Admin controllers
│   └── Order/             # Frontend order form controllers
├── Helper/                 # Helper classes (Context, PriceHelper)
├── Model/                 # Business logic
├── Plugin/                # Stock bypass and pricing plugins (6 total)
├── Setup/                 # Installation scripts
├── Test/
│   └── Integration/       # Integration tests for stock bypass and access control
├── etc/                   # Configuration files
│   ├── adminhtml/        # Admin-specific config
│   ├── frontend/         # Frontend-specific config
│   ├── acl.xml          # ACL resources
│   ├── config.xml       # Default config values
│   ├── di.xml           # Dependency injection
│   └── module.xml       # Module declaration
├── view/                 # Templates and layouts
│   ├── adminhtml/       # Admin views
│   └── frontend/        # Frontend views
├── composer.json        # Composer configuration
├── registration.php     # Module registration
└── README.md           # This file
```

## CSV Export/Import

The Forward Order module provides CSV export/import functionality for efficient bulk ordering.

### Exporting Forward Order Template

1. Navigate to `/forward-order/order` as an eligible dealer customer
2. Click the download icon (↓) in the action bar at the top of the form
3. A modal dialog appears with CSV icon and centered delimiter options:
   - **Standard (Comma)**: Works with Excel, Google Sheets
   - **European (Semicolon)**: For Excel in some regions
4. Save the downloaded `zhik-forward-order-export.csv` file

**Modal Implementation**: Uses Magento UI Modal with instance reuse pattern (prevents duplicate elements). Styling consolidated in theme's `_extend.less` for consistency with Import and Terms modals.

**CSV Export Format**:
```
Name, Parent ID, Color, Size, Barcode, SKU, RRP, Unit Price, Quantity
Product Name, 12345, Red, M, 789012, ABC-123-M-RED, $199.00, $125.50,
```

**Key Points**:
- **Unit Price**: Contains forward order pricing (type 'F'), not Portal trade pricing
- **Quantity**: Empty column for you to fill in with your order quantities
- **Stock Columns Removed**: Forward orders don't check stock, so "Current Stock" and "New Stock Arrival" columns are not included

### Importing Forward Orders

1. Open the exported CSV in Excel, Google Sheets, or similar spreadsheet software
2. Fill in the **Quantity** column for products you want to order
3. Save the file (keep CSV format)
4. Return to `/forward-order/order` page
5. Click the upload icon (↑) in the action bar
6. Import modal opens with:
   - File drag-and-drop upload zone
   - Column mapping (Product Identifier, Quantity)
   - Validation with results table
7. Select your completed CSV file
8. Map columns if needed (auto-detected if headers match)
9. Click "Validate" to check data, then "Import" to apply quantities

**Import Validation**:
- System validates that all products in CSV have forward order pricing
- If any product lacks forward order pricing, import is blocked with error message listing invalid SKUs
- Products not found in catalog are skipped with warning message

### Completing Your Order

After CSV import:
1. Review quantities and prices in the form
2. Make any manual adjustments if needed
3. Select ordering period (required)
4. Accept Terms & Conditions
5. Click "Place Forward Order" button

**Important**: CSV import only sets quantities. The order type 'SF' (Sales Forward) is automatically set when you submit the order - you don't need to do anything special to mark it as a forward order.

### CSV Format Compatibility

The Forward Order CSV format is compatible with Portal's CSV format, with these differences:
- **Removed**: "Current Stock" column (not relevant for forward orders)
- **Removed**: "New Stock Arrival" column (not relevant for forward orders)
- **Pricing**: Unit Price contains forward order prices instead of Portal trade prices

This means you can use the same CSV workflow you're familiar with from the Portal module.

## Development

### Running Tests

```bash
# Unit tests
vendor/bin/phpunit -c dev/tests/unit/phpunit.xml app/code/Zhik/ForwardOrder

# Integration tests (includes CSV export/import tests)
vendor/bin/phpunit -c dev/tests/integration/phpunit.xml app/code/Zhik/ForwardOrder

# Run CSV-specific integration tests
vendor/bin/phpunit -c dev/tests/integration/phpunit.xml app/code/Zhik/ForwardOrder/Test/Integration/CsvExportImportTest.php
```

### Code Standards

This module follows Magento 2 coding standards and Zhik's internal coding guidelines. Run code validation:

```bash
vendor/bin/phpcs --standard=Magento2 app/code/Zhik/ForwardOrder
vendor/bin/phpstan analyse app/code/Zhik/ForwardOrder
```

## Troubleshooting

### Module Not Appearing

1. Check module status:
   ```bash
   bin/magento module:status
   ```

2. Ensure dependencies are installed:
   ```bash
   bin/magento module:status | grep -E "Zhik_(Portal|Myoba)"
   ```

3. Clear cache:
   ```bash
   bin/magento cache:clean
   bin/magento cache:flush
   ```

### Configuration Not Saving

1. Check ACL permissions for the admin user
2. Verify database write permissions
3. Check system.log and exception.log for errors

## Support

For issues or questions, contact the Zhik Development Team at dev@zhik.com

## License

Copyright © Zhik Pty Ltd. All rights reserved.
See LICENSE.txt for license details.