<?php
namespace Lm\Engine\Zaiko\Entity;
use Lm\Engine\Zaiko\Yoyaku;
use Lm\Engine\Zaiko\Zaiko;
use Lm\Entity\Sku;
use Lm\Service\Cache\CacheService;
use Lm\Service\Db\SqlService;
use Lm\Util\Date;
use Lm\Util\Str;
class SkuExtended extends Sku
{
/**
* @return false|string[]
*/
public function getShiiresakiSoukoHanteiAsArray()
{
return Str::csvToArray($this->getShiiresakiSoukoHantei());
}
/**
* @return false|string[]
*/
public function getChokusouIncludeHinbanListAsArray()
{
return Str::csvToArray($this->getChokusouIncludeHinbanList());
}
/**
* @return false|string[]
*/
public function getChokusouExcludeHinbanListAsArray()
{
return Str::csvToArray($this->getChokusouExcludeHinbanList());
}
/**
* @return false|string[]
*/
public function getBichikuIncludeHinbanListAsArray()
{
return Str::csvToArray($this->getBichikuIncludeHinbanList());
}
/**
* @return int
*/
public function getStockAvailability()
{
return self::compute($this->stockAvailability, function () {
//
if ($this->getStockTotal() === null) {
//
return Sku::STOCK_AVL_UNKNOWN;
} else if ($this->getStockTotal() === 0) {
//
return Sku::STOCK_AVL_OUT_OF_STOCK;
} else if ($this->getStockTotal() <= Zaiko::LOW_STOCK_LESS_THAN) {
//
return Sku::STOCK_AVL_LOW_STOCK;
} else {
//
return Sku::STOCK_AVL_IN_STOCK;
}
});
}
/**
* @return int
* @throws \Exception
*/
public function getBackOrder()
{
return self::compute($this->backOrder, function () {
//
if ($nyukaDate = $this->getBichikuNyukaDate() ?: $this->getNyukaDate()) {
//
if (Yoyaku::calculateIsYoyakuAvailable($nyukaDate)) {
//
return Sku::BACK_ORDER_RESERVATION;
} else {
//
return Sku::BACK_ORDER_WAITING;
}
} else {
//
return Sku::BACK_ORDER_UNAVAILABLE;
}
});
}
/**
* @return bool
*/
public function isChokusouAvailable()
{
//
$result = false;
//
if ($this->getIsDirectDeliveryConfigExists() == 1) {
// 直送設定あり
$makerHinban = $this->getMakerHinban();
$lmHinban = $this->getLmHinban();
$makerHinbanCharcters = preg_replace('/[^a-zA-Z]/', '', $makerHinban);
$shiiresakiSoukoCharactersList = $this->getShiiresakiSoukoHanteiAsArray();
$chokusouIncludeHinbanList = $this->getChokusouIncludeHinbanListAsArray();
$chokusouExcludeHinbanList = $this->getChokusouExcludeHinbanListAsArray();
//
if (in_array($lmHinban, $chokusouExcludeHinbanList)) {
// 除外品番
// 無条件で 直送不可 とする
$result = false;
} else if (empty($chokusouIncludeHinbanList) || in_array($lmHinban, $chokusouIncludeHinbanList)) {
// メーカー直送品番(対象商品をLM品番で入力)
$result = true;
} else if (empty($shiiresakiSoukoCharactersList) || in_array($makerHinbanCharcters, $shiiresakiSoukoCharactersList)) {
// メーカー直送品番(該当アルファベット)
$result = true;
}
}
//
return $result;
}
/**
* @return bool
*/
public function isNoDisplay()
{
return $this->getNoDisp() === 1;
}
public static function getInstanceList($goodsId, $janId = null, $gclId = null, $gpId = null, $datetime = null)
{
//
return CacheService::getCached(function () use ($goodsId, $janId, $gclId, $gpId, $datetime) {
//
if (empty($datetime)) {
// 日時の指定が省略された場合、当日の00:00:00が指定されたものとする
$datetime = date(self::DATE_FORMAT_DEFAULT." 00:00:00");
} else {
//
$datetime = Date::getAsDateTime($datetime)->format(self::DATE_TIME_FORMAT_DEFAULT);
}
// セット品番の対応
// TODO: 異なるメーカーを含むセット品番の対応
$goodsSetPurchaseFlg = false;
$childGoodsList = [];
if (!empty($goodsId)) {
//
if ($goods = self::getGoodsInfoByGoodsId($goodsId)) {
// セット品番か否か
// // goodsSetPurchaseFlg = ($goods['goods_set_purchase_flg'] == 1);
// // childGoodsList = array_values(array_filter(explode(',', $goods['child_goods_list']), function ($item) {
// // return trim($item) !== '';
// // ));
} else {
//
throw new \Exception("指定された商品が見つかりません");
}
}
//
if (!empty($childGoodsList)) {
//
$_skuList = self::getGoodsStockInfoByGoodsIdList($childGoodsList, $datetime);
} elseif (!empty($gclId) && !empty($gpId)) {
//
$_skuList = self::getGoodsStockInfoBySkuIdentity($gclId, $gpId, $datetime);
} elseif (!empty($janId)) {
//
$_skuList = self::getGoodsStockInfoByJanId($janId, $datetime);
} elseif (!empty($goodsId)) {
//
$_skuList = self::getGoodsStockInfoByGoodsId($goodsId, $datetime);
} else {
//
throw new \Exception('$goods_id, $jan_id, $gp_id & $gcl_id のいずれかを指定する必要があります');
}
//
$skuList = array_map(function ($_sku) {
//
return new SkuExtended($_sku);
}, $_skuList);
//
return $skuList;
});
}
/**
* @param $goodsId
* @param $janId
* @param $gclId
* @param $gpId
* @param $datetime
* @return mixed
* @throws \Exception
*/
public static function getInstance($goodsId, $janId = null, $gclId = null, $gpId = null, $datetime = null)
{
return CacheService::getCached(function () use ($goodsId, $janId, $gclId, $gpId, $datetime) {
//
$skuList = static::getInstanceList($goodsId, $janId, $gclId, $gpId, $datetime);
//
if (($skuList = array_filter($skuList, function ($sku) use ($janId, $gclId, $gpId) {
/**
* @var SkuExtended $sku
*/
if (!empty($janId)) {
//
return $sku->getJanId() === $janId;
} else if (!empty($gclId) && !empty($gpId)) {
//
return ($sku->getGclId() === (int)$gclId) && ($sku->getGpId() === (int)$gpId);
}
})) && !empty($skuList[0])) {
//
return $skuList[0];
} else {
//
throw new \Exception('SKU情報が見つかりませんでした');
}
});
}
/**
* @param string $datetime
* @param array $bind
* @param string|null $criteria
* @return array|null
*/
protected static function getGoodsStockInfo($datetime, array $bind = [], $criteria = '')
{
//
$bind += [
'datetime' => $datetime,
'yoyaku_available_since_days_ago' => Yoyaku::YOYAKU_AVAILABLE_SINCE_DAYS_AGO,
];
//
$sql = "SELECT
goods_id
, shiiresaki_id
, jan_id
, gcl_id
, gcl_display
, gcl_display_status
, gp_id
, gp_display
, gp_kataban AS `lmHinban`
, jan_shiire_no AS `makerHinban`
, jan_nodisplay AS `noDisp`
, jan_shiire_color
, color_id
, color_name
, size_id
, size_name
, shiiresaki_souko_hantei
, DATE_FORMAT(shiiresaki_shimekiri_time, '%H:%i') AS `timeLimit`
, goods_set_purchase_flg
, (dd_id IS NOT NULL) AS `isDirectDeliveryConfigExists`
, dd_hinban_chokusou AS `chokusouIncludeHinbanList`
, dd_hinban_exclude AS `chokusouExcludeHinbanList`
, dd_hinban_bichiku AS `bichikuIncludeHinbanList`
, `nyuka_date`
, IfNull(`nyuka_date`, '9999-99-99 23:59:59') BETWEEN :datetime AND :datetime + INTERVAL :yoyaku_available_since_days_ago DAY AS `is_yoyaku_available`
, CASE WHEN stock_total > 0 THEN DATE_FORMAT(`bichiku_nyuka_date`, '%Y-%m-%d') ELSE NULL END AS `bichiku_nyuka_date`
, `is_bichiku_ready`
, `is_bichiku_yoyaku_available`
, COALESCE(`stock_total`, '*') AS `stock_total`
, `stock_other`
, COALESCE(NullIf(`stock_bichiku` * `is_bichiku_ready`, 0), NullIf(`stock_chokusou`, 0), 0) AS `stock_sokujitsu`
, `stock_chokusou`
, `stock_bichiku`
, ki_comment AS `nyuka_date_comment`
, cp_price AS `cp_price_in_tax`
, gp_price2 AS `gp_price_ex_tax`
, gp_teika AS `gp_teika_in_tax`
FROM (
SELECT
*
, CASE
WHEN
`stock_total_sub` > 0
THEN
null
ELSE
STR_TO_DATE(`_nyuka_date`, '%Y-%m-%d')
END AS `nyuka_date`
FROM (
SELECT
*
, NullIf(LEAST(IfNull(ki_date, '9999-99-99 23:59:59'), IfNull(zero_period, '9999-99-99 23:59:59')), '9999-99-99 23:59:59') AS `_nyuka_date`
FROM
goods_table AS `goods`
INNER JOIN
shiiresaki_table AS `shiiresaki`
ON
shiiresaki_id = goods_shiiresaki
LEFT JOIN
direct_delivery_table AS `direct_delivery`
ON
shiiresaki_id = dd_shiiresaki
INNER JOIN
goods_color_table AS `gcl`
ON
goods_id = gcl_goods
INNER JOIN
color_table AS `color`
ON
color_id = gcl_color_id
INNER JOIN
goods_price_table AS `gp`
ON
goods_id = gp_goods
INNER JOIN
size_table AS `size`
ON
size_id = gp_size_id
INNER JOIN (
SELECT
`jan`.*
, (
jan_stock
+ IfNull(jan_stock2, 0)
+ IfNull(`stock_bichiku`, 0)
+ IfNull(jan_stock4, 0)
+ IfNull(jan_stock5, 0)
+ IfNull(jan_stock6, 0)
+ IfNull(jan_stock7, 0)
+ IfNull(jan_stock8, 0)
+ IfNull(jan_stock9, 0)
) AS `stock_total`
, (
IfNull(jan_stock4, 0)
+ IfNull(jan_stock5, 0)
+ IfNull(jan_stock6, 0)
+ IfNull(jan_stock7, 0)
+ IfNull(jan_stock8, 0)
+ IfNull(`stock_bichiku`, 0)
) AS `stock_other`
, (
IfNull(`stock_bichiku`, 0)
+ IfNull(jan_stock5, 0)
+ IfNull(jan_stock6, 0)
+ IfNull(jan_stock7, 0)
+ IfNull(jan_stock8, 0)
+ IfNull(jan_stock9, 0)
) AS `stock_total_sub`
, (`stock_bichiku` * `is_bichiku_ready`) AS `stock_bichiku_available`
, (`stock_bichiku` * `is_bichiku_yoyaku_available`) AS `stock_bichiku_yoyaku_available`
FROM (
SELECT
`jan`.*
, NullIf(IfNull(jan_stock3, 0) * `is_jan_stock3_nyuka_date_not_out_date` * (`is_bichiku_ready` || `is_bichiku_yoyaku_available`), 0) AS `stock_bichiku`
FROM (
SELECT
`jan`.*
, CASE WHEN jan_stock != 0 THEN (IfNull(`bichiku_nyuka_date`, '9999-99-99 23:59:59') BETWEEN :datetime AND :datetime + INTERVAL :yoyaku_available_since_days_ago DAY) ELSE bichiku_nyuka_date IS NOT NULL END AS `is_bichiku_yoyaku_available`
FROM (
SELECT
`jan`.*
, (IfNull(jan_stock, 0) + IfNull(jan_stock5, 0) + IfNull(jan_stock7, 0)) AS `stock_chokusou`
, DATE_FORMAT(jan_stock3_nyuka_date + INTERVAL 1 DAY,'%Y-%m-%d %h:%i:%s') AS `bichiku_nyuka_date`
, IfNull(jan_stock, 0) = 0 OR (jan_stock3_nyuka_date IS NULL OR (IfNull(DATE_FORMAT(jan_stock3_nyuka_date + INTERVAL 1 DAY, '%Y-%m-%d'), '0000-00-00') >= DATE_FORMAT(:datetime, '%Y-%m-%d'))) AS `is_jan_stock3_nyuka_date_not_out_date`
, (jan_stock3 IS NOT NULL AND (IfNull(DATE_FORMAT(jan_stock3_nyuka_date, '%Y-%m-%d'), '0000-00-00 00:00:00') < DATE_FORMAT(:datetime, '%Y-%m-%d'))) AS `is_bichiku_ready`
FROM
goods_table AS `goods`
INNER JOIN
goods_color_table AS `gcl`
ON
goods_id = gcl_goods
INNER JOIN
color_table AS `color`
ON
color_id = gcl_color_id
INNER JOIN
goods_price_table AS `gp`
ON
goods_id = gp_goods
INNER JOIN
size_table AS `size`
ON
size_id = gp_size_id
INNER JOIN
jancode_table AS `jan`
ON
goods_id = jan_goods
AND
gcl_id = jan_color
AND
gp_id = jan_price
WHERE
jan_ddate IS NULL
{$criteria}
) AS `jan`
) AS `jan`
) AS `jan`
) AS `jan`
ON
goods_id = jan_goods
AND
gcl_id = jan_color
AND
gp_id = jan_price
LEFT JOIN
keppin_item_table AS `ki`
ON
goods_id = ki_goods
AND
gcl_id = ki_gcl
AND
gp_id = ki_gp
AND
ki_date > :datetime
LEFT JOIN
zero_stock_table AS `zero`
ON
goods_id = zero_goods
AND
gcl_id = zero_gcl
AND
gp_id = zero_gp
AND
zero_period > :datetime
WHERE
goods_ddate IS NULL
{$criteria}
) AS `stock`
) AS `stock`
LEFT JOIN
campaign_price_table
ON
gp_id = cp_gp
AND
cp_start_datetime <= :datetime
AND
cp_end_datetime >= :datetime
AND
cp_del_flg = 0
ORDER BY
goods_id
, gcl_display
, color_display
, gcl_id
, gp_display
, size_display
, gp_id";
//
$result = (new SqlService())
->Sql($sql)
->Params($bind)
->FetchAll() ?: []
;
//
return $result;
}
/**
* @param int $goodsId
* @param string $datetime
* @return array|false
*/
protected static function getGoodsStockInfoByGoodsId($goodsId, $datetime)
{
return CacheService::getCached(function () use ($goodsId, $datetime) {
//
$bind = [
'goods_id' => $goodsId,
];
//
$criteria = "AND
goods_id = :goods_id";
//
$result = self::getGoodsStockInfo($datetime, $bind, $criteria);
//
return $result;
});
}
/**
* @param array $goodsIdList
* @param string $datetime
* @return array|false
*/
protected static function getGoodsStockInfoByGoodsIdList(array $goodsIdList, $datetime)
{
return CacheService::getCached(function () use ($goodsIdList, $datetime) {
//
$bind = [];
foreach ($goodsIdList as $i => $goodsId) {
$bind["goodsId{$i}"] = $goodsId;
}
$placeHolderGoodsIdIn = implode(',', array_map(function ($item) {
return ":{$item}";
}, array_keys($bind)));
//
$criteria = "AND
goods_id IN ({$placeHolderGoodsIdIn})";
//
$result = self::getGoodsStockInfo($datetime, $bind, $criteria);
//
return $result;
});
}
/**
* @param int $janId
* @param string $datetime
* @return array|false
*/
protected static function getGoodsStockInfoByJanId($janId, $datetime)
{
return CacheService::getCached(function () use ($janId, $datetime) {
//
$placeholders = array_map(function ($key) {
//
return "jan_id_{$key}";
}, array_keys((array)$janId));
//
$bind = array_combine($placeholders, (array)$janId);
$placeholdersIn = implode(',', array_map(function ($placeholder) {
//
return ":{$placeholder}";
}, $placeholders));
//
$criteria = "AND
jan_id IN ({$placeholdersIn})";
//
$result = self::getGoodsStockInfo($datetime, $bind, $criteria);
//
return $result;
});
}
/**
* @param int $gclId
* @param int $gpId
* @param string $datetime
* @return array|false
*/
protected static function getGoodsStockInfoBySkuIdentity($gclId, $gpId, $datetime)
{
return CacheService::getCached(function () use ($gclId, $gpId, $datetime) {
//
$bind = [
'gcl_id' => $gclId,
'gp_id' => $gpId,
];
//
$criteria = "AND
gcl_id = :gcl_id
AND
gp_id = :gp_id";
//
$result = self::getGoodsStockInfo($datetime, $bind, $criteria);
//
return $result;
});
}
/**
* @param int $goodsId
* @return mixed
*/
protected static function getGoodsInfoByGoodsId($goodsId)
{
return CacheService::getCached(function () use ($goodsId) {
//
$sql = "SELECT
`parent`.goods_id
, `parent`.goods_set_purchase_flg
, GROUP_CONCAT(DISTINCT `child`.goods_id ORDER BY gsp_type SEPARATOR ',') AS `child_goods_list`
FROM
goods_table AS `parent`
LEFT JOIN
goods_set_purchase_table
ON
`parent`.goods_id = gsp_goods_parent
LEFT JOIN
goods_table AS `child`
ON
`child`.goods_id = gsp_goods_child
WHERE
`parent`.goods_id = :goods_id
GROUP BY
`parent`.goods_id";
//
$bind = [
'goods_id' => $goodsId,
];
//
$result = (new SqlService())
->Sql($sql)
->Params($bind)
->fetch()
;
//
return $result;
});
}
}