142 lines
4.4 KiB
PHP
142 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace Modules\IndustrialEngineering\Services;
|
|
|
|
use App\Product;
|
|
use App\Variation;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Modules\IndustrialEngineering\Models\ItemMaster;
|
|
|
|
/**
|
|
* Links IE item masters to core ERP products/variations for stock, purchase, sales, costing.
|
|
*/
|
|
class ErpItemLinkService
|
|
{
|
|
/**
|
|
* Try to match item to ERP product by SKU or name.
|
|
*
|
|
* @return array{linked: bool, message: string, variation_id?: int}
|
|
*/
|
|
public function autoMatchProduct(ItemMaster $item): array
|
|
{
|
|
if ($item->variation_id) {
|
|
return ['linked' => true, 'message' => __('industrialengineering::lang.auto_erp_already_linked')];
|
|
}
|
|
|
|
$variation = Variation::query()
|
|
->whereHas('product', fn ($q) => $q->where('business_id', $item->business_id))
|
|
->where(function ($q) use ($item) {
|
|
$q->where('sub_sku', $item->item_code)
|
|
->orWhere('sub_sku', 'like', $item->item_code.'%');
|
|
})
|
|
->with('product')
|
|
->first();
|
|
|
|
if (! $variation) {
|
|
$variation = Variation::query()
|
|
->whereHas('product', function ($q) use ($item) {
|
|
$q->where('business_id', $item->business_id)
|
|
->where('name', 'like', '%'.$item->name.'%');
|
|
})
|
|
->with('product')
|
|
->first();
|
|
}
|
|
|
|
if ($variation) {
|
|
$this->linkItem($item, ['variation_id' => $variation->id]);
|
|
|
|
return [
|
|
'linked' => true,
|
|
'message' => __('industrialengineering::lang.auto_erp_matched', ['name' => $this->variationLabel($variation)]),
|
|
'variation_id' => $variation->id,
|
|
];
|
|
}
|
|
|
|
return [
|
|
'linked' => false,
|
|
'message' => __('industrialengineering::lang.auto_erp_not_found', ['code' => $item->item_code]),
|
|
];
|
|
}
|
|
public function linkItem(ItemMaster $item, array $data): ItemMaster
|
|
{
|
|
$updates = [];
|
|
|
|
if (! empty($data['variation_id'])) {
|
|
$variation = Variation::with('product')->find($data['variation_id']);
|
|
if ($variation) {
|
|
$updates['variation_id'] = $variation->id;
|
|
$updates['product_id'] = $variation->product_id;
|
|
if (empty($data['standard_cost']) && $variation->dpp_inc_tax) {
|
|
$updates['standard_cost'] = $variation->dpp_inc_tax;
|
|
}
|
|
if (empty($item->name) || $item->name === $item->item_code) {
|
|
$updates['name'] = $this->variationLabel($variation);
|
|
}
|
|
}
|
|
} elseif (! empty($data['product_id'])) {
|
|
$product = Product::find($data['product_id']);
|
|
if ($product) {
|
|
$updates['product_id'] = $product->id;
|
|
$variation = $product->variations()->first();
|
|
if ($variation) {
|
|
$updates['variation_id'] = $variation->id;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($updates) {
|
|
$item->update($updates);
|
|
}
|
|
|
|
return $item->fresh(['product', 'variation']);
|
|
}
|
|
|
|
public function erpLabel(?ItemMaster $item): ?string
|
|
{
|
|
if (! $item) {
|
|
return null;
|
|
}
|
|
|
|
if ($item->variation_id) {
|
|
$variation = $item->variation ?? Variation::with('product')->find($item->variation_id);
|
|
if ($variation) {
|
|
return $this->variationLabel($variation);
|
|
}
|
|
}
|
|
|
|
if ($item->product_id && ($product = $item->product ?? Product::find($item->product_id))) {
|
|
return $product->name;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function variationLabel(?Variation $variation): string
|
|
{
|
|
if (! $variation) {
|
|
return '';
|
|
}
|
|
|
|
$variation->loadMissing('product');
|
|
$label = $variation->product->name ?? 'محصول';
|
|
if (($variation->product->type ?? '') === 'variable') {
|
|
$label .= ' — '.$variation->name;
|
|
}
|
|
|
|
return $label;
|
|
}
|
|
|
|
public function stockSummary(ItemMaster $item): array
|
|
{
|
|
if (! $item->variation_id) {
|
|
return ['linked' => false, 'qty' => 0];
|
|
}
|
|
|
|
$qty = \DB::table('variation_location_details')
|
|
->where('variation_id', $item->variation_id)
|
|
->sum('qty_available');
|
|
|
|
return ['linked' => true, 'qty' => (float) $qty];
|
|
}
|
|
}
|