Warenwirtschaft: AP-09 bis AP-13 (Produktbestand, Set-Produkte, Ausschuss, Konzepte)
- AP-09 Produktbestand inkl. Bewegungshistorie (product_stock_movements, ProductStockService) - AP-10 Rohstoffbestand-Ansicht je Lager (RawMaterialStockController) - AP-11 Bestandsschwellen / Out-of-Stock-Handling fuer Produkte und Shop - AP-12 Ausgang/Ausschuss (stock_disposals, StockDisposalController, InventoryService) - Set-Produkte (product_set_items) inkl. Aufloesung - Produktentwicklung & Hinweise-Verwaltung (Notices) - AP-13 Entwicklungskonzept Shop-Bestandsabzug im Plan dokumentiert - Feature-Tests fuer neue Module + aktualisierter Entwicklungsplan Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
78679e0c55
commit
3ee2d756e9
63 changed files with 5968 additions and 901 deletions
|
|
@ -33,8 +33,39 @@ class ProductRepository extends BaseRepository
|
|||
$data['whitelabel'] = isset($data['whitelabel']) ? 1 : 0;
|
||||
$data['shipping_addon'] = isset($data['shipping_addon']) ? 1 : 0;
|
||||
$data['max_buy'] = isset($data['max_buy']) ? 1 : 0;
|
||||
$data['no_recipe_required'] = isset($data['no_recipe_required']) ? 1 : 0;
|
||||
$data['is_set'] = isset($data['is_set']) ? 1 : 0;
|
||||
$data['show_on'] = isset($data['show_on']) ? $data['show_on'] : null;
|
||||
|
||||
$data['main_product_quantity'] = isset($data['main_product_quantity']) && $data['main_product_quantity'] !== ''
|
||||
? (int) $data['main_product_quantity']
|
||||
: null;
|
||||
|
||||
// Ein Set ist selbst keine Variante eines Hauptprodukts.
|
||||
$data['main_product_id'] = ! $data['is_set'] && isset($data['main_product_id']) && $data['main_product_id'] !== ''
|
||||
? (int) $data['main_product_id']
|
||||
: null;
|
||||
|
||||
// AP-11: Produktbestand-Schwellwerte (leer => null).
|
||||
$data['min_product_stock'] = isset($data['min_product_stock']) && $data['min_product_stock'] !== ''
|
||||
? max(0, (int) $data['min_product_stock'])
|
||||
: null;
|
||||
$data['critical_product_stock'] = isset($data['critical_product_stock']) && $data['critical_product_stock'] !== ''
|
||||
? max(0, (int) $data['critical_product_stock'])
|
||||
: null;
|
||||
|
||||
// AP-03: „Nicht vorrätig"-Status. „Unbestimmt" hat Vorrang vor der Tagesangabe.
|
||||
$data['out_of_stock_indefinite'] = isset($data['out_of_stock_indefinite']) ? 1 : 0;
|
||||
|
||||
if ($data['out_of_stock_indefinite']) {
|
||||
$data['out_of_stock_until'] = null;
|
||||
} elseif (isset($data['out_of_stock_active']) && isset($data['out_of_stock_days']) && $data['out_of_stock_days'] !== '') {
|
||||
$days = max(0, (int) $data['out_of_stock_days']);
|
||||
$data['out_of_stock_until'] = now()->addDays($days)->startOfDay();
|
||||
} else {
|
||||
$data['out_of_stock_until'] = null;
|
||||
}
|
||||
|
||||
if (array_key_exists('shelf_life_type', $data)) {
|
||||
if ($data['shelf_life_type'] === '' || $data['shelf_life_type'] === null) {
|
||||
$data['shelf_life_type'] = null;
|
||||
|
|
@ -60,14 +91,54 @@ class ProductRepository extends BaseRepository
|
|||
$this->updateWLVariants(isset($data['whitelabel_variants']) ? $data['whitelabel_variants'] : []);
|
||||
$this->updateWLImageAttributs(isset($data['image_wl_attributes']) ? $data['image_wl_attributes'] : [], isset($data['whitelabel_variants']) ? $data['whitelabel_variants'] : []);
|
||||
|
||||
$this->updateIngredients($data);
|
||||
$this->updateManufacturerIngredients($data);
|
||||
$this->updatePackagings($data);
|
||||
if ($this->model->is_set) {
|
||||
// Sets haben keine eigene Rezeptur/Verpackung und werden nicht produziert.
|
||||
ProductIngredient::where('product_id', $this->model->id)->delete();
|
||||
$this->model->packagings()->detach();
|
||||
$this->updateSetItems($data);
|
||||
} else {
|
||||
$this->model->setItems()->detach();
|
||||
$this->updateIngredients($data);
|
||||
$this->updateManufacturerIngredients($data);
|
||||
$this->updatePackagings($data);
|
||||
}
|
||||
|
||||
$this->updateCountryPrices($data);
|
||||
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
public function updateSetItems(array $data = []): bool
|
||||
{
|
||||
if (! isset($data['set_component_id']) || ! is_array($data['set_component_id'])) {
|
||||
$this->model->setItems()->detach();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$ids = $data['set_component_id'];
|
||||
$quantities = $data['set_quantity'] ?? [];
|
||||
$syncData = [];
|
||||
foreach ($ids as $index => $componentId) {
|
||||
$cid = (int) $componentId;
|
||||
if ($cid <= 0 || $cid === (int) $this->model->id) {
|
||||
continue;
|
||||
}
|
||||
$qty = (int) ($quantities[$index] ?? 1);
|
||||
if ($qty < 1) {
|
||||
$qty = 1;
|
||||
}
|
||||
$syncData[$cid] = [
|
||||
'quantity' => $qty,
|
||||
'pos' => (int) $index,
|
||||
];
|
||||
}
|
||||
|
||||
$this->model->setItems()->sync($syncData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updatePackagings(array $data = []): bool
|
||||
{
|
||||
if (! isset($data['pp_packaging_item_id']) || ! is_array($data['pp_packaging_item_id'])) {
|
||||
|
|
@ -400,6 +471,17 @@ class ProductRepository extends BaseRepository
|
|||
}
|
||||
$this->model->packagings()->sync($packSync);
|
||||
|
||||
$setSync = [];
|
||||
foreach ($model->setItems()->get() as $component) {
|
||||
$setSync[$component->id] = [
|
||||
'quantity' => $component->pivot->quantity !== null ? (int) $component->pivot->quantity : 1,
|
||||
'pos' => (int) ($component->pivot->pos ?? 0),
|
||||
];
|
||||
}
|
||||
if ($setSync !== []) {
|
||||
$this->model->setItems()->sync($setSync);
|
||||
}
|
||||
|
||||
foreach ($model->country_prices as $cp) {
|
||||
CountryPrice::create([
|
||||
'country_id' => $cp->country_id,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue