クラス
PurchaseSanityChecks
ソース ソース
ファイル: src/API/PurchaseSanityChecks.php
class PurchaseSanityChecks { /** * Registers hooks * * @author Evan D Shaw <evandanielshaw@gmail.com> * @return void */ public static function init() { add_filter('usces_filter_zaiko_check', [get_class(), 'checkComboSetItems'], 10, 2); } /** * Runs validation checks for each combo-set item in the cart (if applicable) * * @author Evan D Shaw <evandanielshaw@gmail.com> * @param string $mes * @param array $cart * @return string */ public static function checkComboSetItems($mes, $cart) { // just quit if none of the cart items are combo-sets $found = false; foreach ($cart as $crow) { $sels = unserialize($crow['serial']); if (!empty($sels['comboSetId']) && !empty($sels['comboSetItems'])) { $found = true; break; } } if ($found === false) { return $mes; } $divcheckmes = self::checkDivisions($cart); if (!empty($divcheckmes)) { return $divcheckmes; } return self::checkCartItemsInventory($mes, $cart); } /** * Check combo-set and group item divisions to ensure compatability * * @author Evan D Shaw <evandanielshaw@gmail.com> * @param array $cart * @return string */ public static function checkDivisions($cart) { $mes = ''; foreach ($cart as $i => $cart_row) { $sels = unserialize($cart_row['serial']); $mapifiedselections = []; $errors = []; if (!empty($sels['comboSetId']) && !empty($sels['comboSetItems'])) { foreach ($sels['comboSetItems'] as $giserial => $gitem) { $data = unserialize($giserial); $mapifiedselections[$data['groupId']][] = $data['itemId']; $result = self::comboSetItemDivisionIsValid($sels['comboSetId'], $mapifiedselections); if ($result instanceof GenericError) { $errors[] = $result->message; } } } $mes .= self::constructIndexedErrorMessage($i, $errors); } return $mes; } /** * Checks stock for each cart item and each group item in a combo-set * * @author Evan D Shaw <evandanielshaw@gmail.com> * @global \usc_e_shop $usces * @param string $mes * @param array $cart * @return string */ public static function checkCartItemsInventory($mes, $cart) { global $usces; // just quit if none of the cart items are combo-sets $found = false; foreach ($cart as $crow) { $sels = unserialize($crow['serial']); if (!empty($sels['comboSetId']) && !empty($sels['comboSetItems'])) { $found = true; break; } } if ($found === false) { return $mes; } $mes = ''; $stocks = []; foreach ($cart as $i => $cart_row) { $rowmes = ''; $sels = unserialize($cart_row['serial']); $cart_row = $cart[$i]; $post_id = $cart_row['post_id']; $sku = $cart_row['sku']; $sku_code = urldecode($cart_row['sku']); $quant = isset($_POST['quant'][$i][$post_id][$sku]) ? (int)trim($_POST['quant'][$i][$post_id][$sku]) : $cart_row['quantity']; $stock = $usces->getItemZaikoNum($post_id, $sku_code); if (!isset($stocks[$post_id][$sku])) { if (!\WCUtils::is_blank($stock)) { $stocks[$post_id][$sku] = $stock; } else { $stocks[$post_id][$sku] = null; } } $checkstock = $stocks[$post_id][$sku]; $stocks[$post_id][$sku] = $stocks[$post_id][$sku] - $quant; $product = wel_get_product($post_id); $itemRestriction = isset($product['itemRestriction']) ? $product['itemRestriction'] : ''; $itemOrderAcceptable = $usces->getItemOrderAcceptable($post_id); $post_status = get_post_status($post_id); if (1 > (int)$quant) { $rowmes .= sprintf(__('Enter the correct amount for the No.%d item.', 'usces'), ($i + 1)) . '<br />'; } elseif (!$usces->is_item_zaiko($post_id, $sku_code) || ($itemOrderAcceptable != 1 && \WCUtils::is_zero($stock)) || 'publish' != $post_status) { $rowmes .= sprintf(__('Sorry, No.%d item is sold out.', 'usces'), ($i + 1)) . '<br />'; } elseif ($quant > (int)$itemRestriction && !\WCUtils::is_blank($itemRestriction) && !\WCUtils::is_zero($itemRestriction)) { $rowmes .= sprintf(__('This article is limited by %1$d at a time for the No.%2$d item.', 'usces'), $itemRestriction, ($i + 1)) . '<br />'; } elseif ($itemOrderAcceptable != 1 && 0 > $stocks[$post_id][$sku] && !\WCUtils::is_blank($stock)) { $rowmes .= sprintf(__('Stock of No.%1$d item is remainder %2$d.', 'usces'), ($i + 1), $checkstock) . '<br />'; } $mes .= $rowmes; if ((int)$quant > 0 && empty($rowmes)) { $gierrors = []; if (!empty($sels['comboSetId']) && !empty($sels['comboSetItems'])) { $mapifiedselections = []; foreach ($sels['comboSetItems'] as $giserial => $gitem) { $data = unserialize($giserial); $mapifiedselections[$data['groupId']][] = $data['itemId']; } $result = self::comboSetSelectionsAreValid($sels['comboSetId'], $mapifiedselections); if ($result instanceof GenericError) { $message = $result->message; if ($result->errorcode === ErrorStore::COMBO_GROUP_IS_REQUIRED) { $message = __('Selections for this combo-set item have been updated. Please refresh the page and try again.', 'wcexics'); } $gierrors[] = $message; } else { $giindex = 0; foreach ($sels['comboSetItems'] as $giserial => $gitem) { $gitemquant = $sels['comboSetItems'][$giserial]['quant'] * $quant; $gicrow = (new \usces_cart())->key_unserialize($giserial); $gipost_id = $gicrow['post_id']; $gisku = $gicrow['sku']; $gisku_code = urldecode($gicrow['sku']); $stock = $usces->getItemZaikoNum($gipost_id, $gisku_code); if (!isset($stocks[$gipost_id][$gisku])) { if (!\WCUtils::is_blank($stock)) { $stocks[$gipost_id][$gisku] = $stock; } else { $stocks[$gipost_id][$gisku] = null; } } $checkstock = $stocks[$gipost_id][$gisku]; $stocks[$gipost_id][$gisku] = $stocks[$gipost_id][$gisku] - $gitemquant; $giproduct = wel_get_product($gipost_id); $itemRestriction = isset($giproduct['itemRestriction']) ? $giproduct['itemRestriction'] : ''; $itemOrderAcceptable = $usces->getItemOrderAcceptable($gipost_id); $post_status = get_post_status($gipost_id); if (!$usces->is_item_zaiko($gipost_id, $gisku_code) || ($itemOrderAcceptable != 1 && \WCUtils::is_zero($stock)) || 'publish' != $post_status) { $gierrors[] = sprintf(__('Sorry, No.%d item is sold out.', 'usces'), ($giindex + 1)); } elseif ($gitemquant > (int)$itemRestriction && !\WCUtils::is_blank($itemRestriction) && !\WCUtils::is_zero($itemRestriction)) { $gierrors[] = sprintf(__('This article is limited by %1$d at a time for the No.%2$d item.', 'usces'), $itemRestriction, ($giindex + 1)); } elseif ($itemOrderAcceptable != 1 && 0 > $stocks[$gipost_id][$gisku] && !\WCUtils::is_blank($stock)) { $gierrors[] = sprintf(__('Stock of No.%1$d item is remainder %2$d.', 'usces'), ($giindex + 1), $checkstock); } $giindex++; } } } $mes .= self::constructIndexedErrorMessage($i, $gierrors); } } return $mes; } /** * Checks for existence of the combo-set. Also checks for the existence of each group and item and * checks that required groups have at least one selection. * * @author Evan D Shaw <evandanielshaw@gmail.com> * @param int $comboSetId * @param array $grouptoitemmap * @return GenericError|true */ public static function comboSetSelectionsAreValid($comboSetId, $grouptoitemmap) { $comboSetId = (int)$comboSetId; $comboset = ComboSet::getComboSetById($comboSetId); if ($comboset instanceof GenericError) { return $comboset; } $grouptoitemmap = Cart::sanitizeComboSetSelections($grouptoitemmap); // check that all required groups have selections foreach ($comboset->getGroups() as $group) { if ($group->getOptional() === false) { // if the required group has at least one item but no item is selected, abort if (count($group->getItems()) > 0 && empty($grouptoitemmap[$group->getId()])) { return Master::getErrorStore()->getErrorResponse( ErrorStore::COMBO_GROUP_IS_REQUIRED, [$group], [$group], [$group] ); } } } // check that all selected groups and items exist foreach ($grouptoitemmap as $groupid => $itemids) { $group = ComboGroup::getComboGroupById($groupid); // if the group does not exist OR it is not associated with the combo-set, abort if ($group === null || $group->getComboSetId() !== $comboset->getId()) { return Master::getErrorStore()->getErrorResponse( ErrorStore::COMBO_GROUP_NOT_FOUND, [$groupid], [], [$groupid] ); } foreach ($itemids as $itemid) { $item = GroupItem::getGroupItemById($itemid); // if the item does not exist OR it is not associated with the group, abort if ($item === null || $item->getGroupId() !== $group->getId()) { return Master::getErrorStore()->getErrorResponse( ErrorStore::GROUP_ITEM_NOT_FOUND, [$itemid], [], [$itemid] ); } } } return true; } /** * Checks validity of item divisions * * @author Evan D Shaw <evandanielshaw@gmail.com> * @global \usc_e_shop $usces * @param int $comboSetId * @param array $grouptoitemmap * @return GenericError|true */ public static function comboSetItemDivisionIsValid($comboSetId, $grouptoitemmap) { global $usces; $comboSetId = (int)$comboSetId; $comboset = ComboSet::getComboSetById($comboSetId); if ($comboset instanceof GenericError) { return $comboset; } $grouptoitemmap = Cart::sanitizeComboSetSelections($grouptoitemmap); $division = strtolower((string)$usces->getItemDivision($comboset->getPostId())); if ($division === 'shipped') { $notshipped = false; foreach ($grouptoitemmap as $groupid => $itemids) { $group = ComboGroup::getComboGroupById($groupid); if (empty($group)) { continue; } foreach ($itemids as $itemid) { $item = GroupItem::getGroupItemById($itemid); if (empty($item)) { continue; } $gidivision = strtolower((string)$usces->getItemDivision($item->getPostId())); if ($gidivision !== $division) { $notshipped = $gidivision; break; } } if ($notshipped !== false) { break; } } if ($notshipped !== false) { $dvars = [ $division, $gidivision, __('The division of each group item for a combo-set with division "shipped" must also be "shipped"', 'wcexics'), ]; $error = Master::getErrorStore()->getErrorResponse( ErrorStore::COMBO_SET_DIVISION_INVALID, $dvars, [], $dvars ); $error->setLogger(new Logger())->setData(array_merge( $comboset->getDataForLog(), ['groupItemSelections' => $grouptoitemmap] )); $error->logger->error($error); return $error; } } return true; } /** * Checks validity of item charge types * * @author Evan D Shaw <evandanielshaw@gmail.com> * @global \usc_e_shop $usces * @param int $comboSetId * @param array $grouptoitemmap * @return GenericError|true */ public static function comboSetItemChargeTypeIsValid($comboSetId, $grouptoitemmap) { global $usces; $comboSetId = (int)$comboSetId; $comboset = ComboSet::getComboSetById($comboSetId); if ($comboset instanceof GenericError) { return $comboset; } $chargetype = strtolower((string)$usces->getItemChargingType($comboset->getPostId())); if ($chargetype === 'once') { $grouptoitemmap = Cart::sanitizeComboSetSelections($grouptoitemmap); foreach ($grouptoitemmap as $groupid => $itemids) { $group = ComboGroup::getComboGroupById($groupid); if (empty($group)) { continue; } foreach ($itemids as $itemid) { $item = GroupItem::getGroupItemById($itemid); if (empty($item)) { continue; } $gichargetype = strtolower((string)$usces->getItemChargingType($item->getPostId())); if ($gichargetype === 'continue') { $mvars = [__('Normal Charging', 'dlseller'), __('Continuation Charging', 'dlseller')]; $error = Master::getErrorStore()->getErrorResponse( ErrorStore::INVALID_CHARGE_TYPE_COMBINATION, $mvars, [], $mvars ); $error->setLogger(new Logger())->setData([ 'comboSet' => $comboset->getDataForLog(), 'welitemSkuMetaId' => $item->getSkuMetaId(), ]); return $error; } } } } return true; } /** * Constructs an indexed error message for the cart page * * @author Evan D Shaw <evandanielshaw@gmail.com> * @param int $i * @param array $gierrors * @return string */ public static function constructIndexedErrorMessage($i, $gierrors) { $mes = ''; if (empty($gierrors)) { return $mes; } $mes .= '<div class="wcexics combo-set-cart-errors">'; $mes .= '<div class="combo-set-cart-errors__title">' . sprintf( // translators: The combo-set cart item index __('Combo-set No. %d encountered the following problems:', 'wcexics'), ($i + 1) ); $mes .= '</div>'; $mes .= '<ul>'; $gierrors = array_map(function ($e) { return '<li>' . $e . '</li>'; }, $gierrors); $mes .= join('', $gierrors); $mes .= '</ul>'; $mes .= '</div>'; return $mes; } /** * Exits to item page with an error message * * This method mirrors the exit logic in `$usces->incart_check()`. If only * the exit logic existed in its own function we could call it directly...... * * @author Evan D Shaw <evandanielshaw@gmail.com> * @param string $message * @return void */ public static function exitAddToCartWithError($message) { $ids = array_keys($_POST['inCart']); $post_id = $ids[0]; $skus = array_keys($_POST['inCart'][$post_id]); $sku = urldecode($skus[0]); $_SESSION['usces_singleitem']['error_message'] = [$post_id => [$sku => $message]]; $url = esc_url($_POST['usces_referer']); if (false === strpos($_POST['usces_referer'], 'http')) { $parse_url = parse_url(get_home_url()); $port = ''; if ($parse_url['host'] === 'localhost' && !empty($parse_url['port'])) { $port = ':' . $parse_url['port']; } $url = $parse_url['scheme'] . '://' . $parse_url['host'] . $port . $url; } header('location: ' . $url . apply_filters('usces_filter_incart_redirect', '#cart_button', $post_id, $sku)); exit; } }
- checkCartItemsInventory — Checks stock for each cart item and each group item in a combo-set
- checkComboSetItems — Runs validation checks for each combo-set item in the cart (if applicable)
- checkDivisions — Check combo-set and group item divisions to ensure compatability
- comboSetItemChargeTypeIsValid — Checks validity of item charge types
- comboSetItemDivisionIsValid — Checks validity of item divisions
- comboSetSelectionsAreValid — Checks for existence of the combo-set. Also checks for the existence of each group and item and checks that required groups have at least one selection.
- constructIndexedErrorMessage — Constructs an indexed error message for the cart page
- exitAddToCartWithError — Exits to item page with an error message
- init — Registers hooks