d2d.emegrendeles.hu/app/Services/NextDeliveryDateCalculatorService.php
E98Developer d26ba5e5e6 FIX EV3-466 hétvégi szállítási napok engedélyezése a heti sablonból
A DeliveryCalendarService 4. prioritása a WorkCalendarService::isWorkDay()-t
hívta, ami a naptárban nem szereplő napoknál a hétvégére esett vissza. Így egy
hétvégét is tartalmazó sablon szombat/vasárnap mezőit sosem érte el a
kiértékelés (5. prioritás), és csak egyedi felülbírálással lehetett hétvégi
szállítást engedni.

- WorkCalendarService: új isHoliday(), ami csak a work_calendars ünnepnap
  rekordjaira ad true-t, a naptári hétvégére nem. Az isWorkDay() változatlan.
- DeliveryCalendarService: a 4. prioritás mostantól isHoliday()-t használ, így
  a hétvégéről a heti sablon dönt. Ünnepnap továbbra is tilt.
- NextDeliveryDateCalculatorService: a szállítási nap keresése kikerült az
  isWorkDay() blokkból, különben a hétvége a következő szállítási nap
  számításánál továbbra is kimaradt volna. Az átfutási időbe az új
  countsTowardLeadTime() szerint a sablon hétvégi napjai is beleszámítanak,
  a H-P sablonok viselkedése változatlan.
- DeliveryCalendarWidget: a szürke "inaktív" festés csak a nem szállítási
  hétvégékre megy rá. Mellékesen a szállítási napok ciklusa $date->addDay()-jel
  mutálta a kollekció Carbon objektumait, ez copy()-ra javítva.

7 új teszt, köztük a H-P sablon regresszió-őre.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 15:59:59 +02:00

127 lines
4.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use App\Models\ProfitCenter;
use App\Models\ProfitCenterSupplierSchedule;
use App\Models\Supplier;
use Illuminate\Support\Carbon;
class NextDeliveryDateCalculatorService extends ServiceBase
{
public function __construct(
protected DeliveryCalendarService $deliveryCalendarService,
protected WorkCalendarService $workCalendarService,
) {
}
/**
* Meghatározza a következő szállítási napot egy adott supplierprofitcenter párosnál,
* a megrendelés leadásának dátuma és időpontja alapján.
*
* Ha a suppliernek van szállítási korlátozása (hasDeliveryConstraint), figyelembe veszi:
* - orderCutOffTime: leadási határidő (óra), ha előtte adjuk le, a nap beleszámít az átfutásba
* - deliveryLeadTime: szállítási átfutási idő (óra → munkanapban számítva)
*
* @param int $supplierId
* @param int $profitCenterId
* @param Carbon $orderDateTime A leadás dátuma és időpontja
* @return Carbon|null A következő lehetséges szállítási nap
*/
public function calculate(
int $supplierId,
int $profitCenterId,
Carbon $orderDateTime
): ?Carbon {
$assignment = ProfitCenterSupplierSchedule::where('supplier_id', $supplierId)
->where('profit_center_id', $profitCenterId)
->with('deliverySchedule')
->first();
if (! $assignment?->deliverySchedule) {
return null;
}
$supplier = Supplier::find($supplierId);
$pc = ProfitCenter::find($profitCenterId);
if (! $supplier || ! $pc) {
return null;
}
$leadDays = 0;
$startDay = $orderDateTime->copy()->startOfDay();
if ($supplier->hasDeliveryConstraint) {
$cutOffHour = (int) $supplier->orderCutOffTime;
$leadDays = (int) ($supplier->deliveryLeadTime / 24);
// Ha a leadási határidő UTÁN vagyunk, holnap az első számítandó munkanap
if ($orderDateTime->hour >= $cutOffHour) {
$startDay->addDay();
}
}
return $this->findNextDeliveryDay($startDay, $supplier, $pc, $leadDays, $assignment);
}
/**
* Előreszámol $leadDays darab átfutási napot, majd az első olyan napot adja vissza,
* amelyik szállítási nap is.
*
* A szállítási nap keresése NINCS munkanaphoz kötve: hétvégi szállítást a heti sablon
* engedhet, ezt az isDeliveryDay() dönti el (EV3-466).
*/
private function findNextDeliveryDay(
Carbon $candidate,
Supplier $supplier,
ProfitCenter $pc,
int $leadDays,
ProfitCenterSupplierSchedule $assignment,
): ?Carbon {
$leadDaysCounted = 0;
// Max. 365 nap iteráció (végtelen ciklus-védelem)
for ($i = 0; $i < 365; $i++) {
if ($leadDaysCounted >= $leadDays) {
// Átfutási idő letelt az első szállítási napot keressük
if ($this->deliveryCalendarService->isDeliveryDay($pc, $supplier, $candidate, $assignment)) {
return $candidate->copy();
}
} elseif ($this->countsTowardLeadTime($candidate, $assignment)) {
$leadDaysCounted++;
}
$candidate->addDay();
}
return null;
}
/**
* Eldönti, hogy az adott nap beleszámít-e az átfutási idő visszaszámolásába.
*
* A hivatalos munkanapokon túl beleszámítanak azok a hétvégi napok is, amelyeket a
* PC-hez rendelt heti sablon szállítási napként jelöl egy 7 napos sablonnál tehát
* minden nap telik, egy HP sablonnál viszont a hétvége változatlanul nem (EV3-466).
* Munkaszüneti napon sosem telik az átfutás.
*/
private function countsTowardLeadTime(Carbon $date, ProfitCenterSupplierSchedule $assignment): bool
{
if ($this->workCalendarService->isHoliday($date)) {
return false;
}
if ($this->workCalendarService->isWorkDay($date)) {
return true;
}
$schedule = $assignment->deliverySchedule;
if (! $schedule || ! $schedule->is_active) {
return false;
}
return (bool) $schedule->{strtolower($date->format('l'))};
}
}