@extends('layouts.app') @section('title', __('product.import_products')) @section('content')

@lang('product.import_products')

@if (session('notification') || !empty($notification))
@if(!empty($notification['msg'])) {{$notification['msg']}} @elseif(session('notification.msg')) {{ session('notification.msg') }} @endif
@endif
@component('components.widget', ['class' => 'box-primary']) {!! Form::open(['url' => action([\App\Http\Controllers\ImportProductsController::class, 'store']), 'method' => 'post', 'enctype' => 'multipart/form-data' ]) !!}
{!! Form::label('name', __( 'product.file_to_import' ) . ':') !!} {!! Form::file('products_csv', ['accept'=> '.xls, .xlsx, .csv', 'required' => 'required']); !!}

{{-- Two switches that matter for a large first load: validate the whole file before committing anything, and decide whether unknown manufacturers/divisions/compositions are created or rejected. --}}
{!! Form::close() !!}

{{-- Generated from ImportProductsController::templateColumns() so the template can never drift from the parser. The old link pointed at a file that did not exist in the repo. --}} @lang('lang_v1.download_template_file')

The template includes two SAMPLE rows (a single and a variable product) showing how to fill each column — delete both before adding your own products and uploading.

@endcomponent
@component('components.widget', ['class' => 'box-primary', 'title' => __('lang_v1.instructions')]) @lang('lang_v1.instruction_line1')
@lang('lang_v1.instruction_line2')

{{-- 45-57, added 2026-08 to close the gap against the product form. All optional: a file built from the older 44-column template still imports unchanged. --}}
@lang('lang_v1.col_no') @lang('lang_v1.col_name') @lang('lang_v1.instruction')
1 @lang('product.product_name') (@lang('lang_v1.required')) @lang('lang_v1.name_ins')
2 @lang('product.brand') (@lang('lang_v1.optional')) @lang('lang_v1.brand_ins')
(@lang('lang_v1.brand_ins2'))
3 @lang('product.unit') (@lang('lang_v1.required')) @lang('lang_v1.unit_ins')
4 @lang('product.category') (@lang('lang_v1.optional')) @lang('lang_v1.category_ins')
(@lang('lang_v1.category_ins2'))
5 @lang('product.sub_category') (@lang('lang_v1.optional')) @lang('lang_v1.sub_category_ins')
({!! __('lang_v1.sub_category_ins2') !!})
6 @lang('product.sku') (@lang('lang_v1.optional')) @lang('lang_v1.sku_ins')
7 @lang('product.barcode_type') (@lang('lang_v1.optional'), @lang('lang_v1.default'): C128) @lang('lang_v1.barcode_type_ins')
@lang('lang_v1.barcode_type_ins2'): C128, C39, EAN-13, EAN-8, UPC-A, UPC-E, ITF-14
8 @lang('product.manage_stock') (@lang('lang_v1.required')) @lang('lang_v1.manage_stock_ins')
1 = @lang('messages.yes')
0 = @lang('messages.no')
9 @lang('product.alert_quantity') (@lang('lang_v1.optional')) @lang('product.alert_quantity')
10 @lang('product.expires_in') (@lang('lang_v1.optional')) @lang('lang_v1.expires_in_ins')
11 @lang('lang_v1.expire_period_unit') (@lang('lang_v1.optional')) @lang('lang_v1.expire_period_unit_ins')
@lang('lang_v1.available_options'): days, months
12 @lang('product.applicable_tax') (@lang('lang_v1.optional')) @lang('lang_v1.applicable_tax_ins') {!! __('lang_v1.applicable_tax_help') !!}
13 @lang('product.selling_price_tax_type') (@lang('lang_v1.required')) @lang('product.selling_price_tax_type')
@lang('lang_v1.available_options'): inclusive, exclusive
14 @lang('product.product_type') (@lang('lang_v1.required')) @lang('product.product_type')
@lang('lang_v1.available_options'): single, variable
15 @lang('product.variation_name') (@lang('lang_v1.variation_name_ins')) @lang('lang_v1.variation_name_ins2')
16 @lang('product.variation_values') (@lang('lang_v1.variation_values_ins')) {!! __('lang_v1.variation_values_ins2') !!}
17 @lang('lang_v1.variation_sku') (@lang('lang_v1.optional')) {!! __('lang_v1.variation_sku_ins') !!}
18 @lang('lang_v1.purchase_price_inc_tax')
(@lang('lang_v1.purchase_price_inc_tax_ins1'))
{!! __('lang_v1.purchase_price_inc_tax_ins2') !!}
19 @lang('lang_v1.purchase_price_exc_tax')
(@lang('lang_v1.purchase_price_exc_tax_ins1'))
{!! __('lang_v1.purchase_price_exc_tax_ins2') !!}
20 @lang('lang_v1.profit_margin') (@lang('lang_v1.optional')) @lang('lang_v1.profit_margin_ins')
{!! __('lang_v1.profit_margin_ins1') !!}
21 @lang('lang_v1.selling_price') (@lang('lang_v1.optional')) @lang('lang_v1.selling_price_ins')
{!! __('lang_v1.selling_price_ins1') !!}
22 @lang('lang_v1.opening_stock') (@lang('lang_v1.optional')) @lang('lang_v1.opening_stock_ins') {!! __('lang_v1.opening_stock_help_text') !!}
23 @lang('lang_v1.opening_stock_location') (@lang('lang_v1.optional'))
@lang('lang_v1.location_ins')
@lang('lang_v1.location_ins1')
24 @lang('lang_v1.expiry_date') (@lang('lang_v1.optional')) {!! __('lang_v1.expiry_date_ins') !!}
25 @lang('lang_v1.enable_imei_or_sr_no') (@lang('lang_v1.optional'), @lang('lang_v1.default'): 0) 1 = @lang('messages.yes')
0 = @lang('messages.no')

26 @lang('lang_v1.weight') (@lang('lang_v1.optional')) @lang('lang_v1.optional')
27 @lang('lang_v1.rack') (@lang('lang_v1.optional')) {!! __('lang_v1.rack_help_text') !!}
28 @lang('lang_v1.row') (@lang('lang_v1.optional')) {!! __('lang_v1.row_help_text') !!}
29 @lang('lang_v1.position') (@lang('lang_v1.optional')) {!! __('lang_v1.position_help_text') !!}
30 @lang('lang_v1.image') (@lang('lang_v1.optional')) {!! __('lang_v1.image_help_text', ['path' => 'public/uploads/'.config('constants.product_img_path')]) !!}

{{__('lang_v1.img_url_help_text')}}
31 @lang('lang_v1.product_description') (@lang('lang_v1.optional'))
32 @lang('lang_v1.product_custom_field1') (@lang('lang_v1.optional'))
33 @lang('lang_v1.product_custom_field2') (@lang('lang_v1.optional'))
34 @lang('lang_v1.product_custom_field3') (@lang('lang_v1.optional'))
35 @lang('lang_v1.product_custom_field4') (@lang('lang_v1.optional'))
36 @lang('lang_v1.not_for_selling') (@lang('lang_v1.optional')) 1 = @lang('messages.yes')
0 = @lang('messages.no')

37 @lang('lang_v1.product_locations') (@lang('lang_v1.optional')) @lang('lang_v1.product_locations_ins')
38 Drug Schedule (@lang('lang_v1.optional')) @lang('lang_v1.available_options'): H, H1, X, G, J, OTC
Schedules H, H1 and X automatically mark the product as prescription-required.
39 HSN Code (@lang('lang_v1.optional')) HSN / SAC tax code of the product.
40 Dosage Form (@lang('lang_v1.optional')) e.g. tablet, capsule, syrup, injection, ointment.
41 Storage Condition (@lang('lang_v1.optional')) e.g. cool_dry_place, refrigerate, room_temperature.
42 Manufacturer (@lang('lang_v1.optional')) Name of an existing manufacturer. Must match a manufacturer already created in the system.
43 Division (@lang('lang_v1.optional')) Name of an existing division. Must match a division already created in the system.
44 Composition (@lang('lang_v1.optional')) Name of an existing composition / salt, or any name when @lang('lang_v1.create_missing_masters') is ticked.
45 Opening Stock Sub-unit (@lang('lang_v1.optional')) Unit the Opening Stock figure (column 22) is expressed in, e.g. Baby Box. The quantity is converted to base units using that unit's multiplier.
46 MRP (inc. tax) (@lang('lang_v1.optional')) Maximum Retail Price printed on the pack. Leave blank only if the product has no MRP — it is required on pharmacy invoices and labels.
47 Mfg Lead Time (days) (@lang('lang_v1.optional')) Whole days from PO date for the product to reach the warehouse from the manufacturer. Drives the PO Follow-up ETA. Blank = unknown (the observed average is used instead); not the same as 0.
48 Sub-units (@lang('lang_v1.optional')) Comma separated unit names that this product can be transacted in, e.g. Strip(1/15),Baby Box(1/15). Required for pack-based selling and for auto-PO rounding to whole packs.
Each must be a sub-unit of the unit in column 3 — that is, its Base Unit under Products > Units must be that same unit. A pack belonging to a different base unit is rejected, because it would be stored and then ignored everywhere it matters.
Consequently column 3 must hold the base unit (e.g. Tablets), never a pack, whenever this column is used.
49 Sellable Units (@lang('lang_v1.optional')) Subset of column 48 (plus the base unit) that may be sold. Blank = all of them. A name that is neither the base unit nor one of the sub-units listed in column 48 is rejected.
50 Purchasable Units (@lang('lang_v1.optional')) Subset of column 48 (plus the base unit) that may be purchased. Blank = all of them. A name that is neither the base unit nor one of the sub-units listed in column 48 is rejected.
51 Default Sell Unit (@lang('lang_v1.optional')) Pre-selected unit at POS. Must be the base unit or one from column 48, and inside column 49 when that is set.
52 Default Purchase Unit (@lang('lang_v1.optional')) Pre-selected unit at purchase entry. Same rules against columns 48 and 50.
53 Secondary Unit (@lang('lang_v1.optional')) Name of an existing unit, used as the product's secondary unit.
54 Manufacturers (@lang('lang_v1.optional')) Comma separated list of every manufacturer that makes this product — the first is the primary. A warehouse purchase order can then be placed on any of them. Overrides column 42 when both are filled.
55 Can be purchased? (@lang('lang_v1.optional')) 1 = @lang('messages.yes'), 0 = @lang('messages.no'). Blank keeps the default (yes).
56 Can be stored? (@lang('lang_v1.optional')) 1 = @lang('messages.yes'), 0 = @lang('messages.no'). Blank keeps the default (yes).
57 Product Tags (@lang('lang_v1.optional')) Comma separated tags.
@endcomponent
@endsection