Source of file OrderAttribute.php
Size: 14,299 Bytes - Last Modified: 2021-12-23T10:39:35+00:00
/var/www/docs.ssmods.com/process/src/src/Model/OrderAttribute.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 | <?php namespace Sunnysideup\Ecommerce\Model; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Config\Config; use SilverStripe\ORM\DataObject; use SilverStripe\Security\Permission; use SilverStripe\Security\Security; use Sunnysideup\CmsEditLinkField\Api\CMSEditLinkAPI; use Sunnysideup\Ecommerce\Api\ShoppingCart; use Sunnysideup\Ecommerce\Config\EcommerceConfigAjax; use Sunnysideup\Ecommerce\Config\EcommerceConfigAjaxDefinitions; use Sunnysideup\Ecommerce\Config\EcommerceConfigClassNames; use Sunnysideup\Ecommerce\Interfaces\EditableEcommerceObject; use Sunnysideup\Ecommerce\Model\Extensions\EcommerceRole; use Sunnysideup\Ecommerce\Model\Money\EcommerceCurrency; use Sunnysideup\Ecommerce\Tasks\EcommerceTaskDebugCart; use Sunnysideup\Ecommerce\Traits\OrderCached; /** * @description: base class for OrderItem (item in cart) and OrderModifier (extra - e.g. Tax) * * @see OrderModifier * @see OrderItem * * @authors: Nicolaas [at] Sunny Side Up .co.nz * @package: ecommerce * @sub-package: model */ class OrderAttribute extends DataObject implements EditableEcommerceObject { use OrderCached; /** * save edit status for speed's sake. * * @var null|bool */ protected $_canEdit; /** * save view status for speed's sake. * * @var null|bool */ protected $_canView; /** * we use this variable to make sure that the parent::runUpdate() is called in all child classes * this is similar to the checks run for parent::init in the controller class. * * @var bool */ protected $baseInitCalled = false; /** * what variables are accessible through http://mysite.com/api/ecommerce/v1/ShippingAddress/. * * @var array */ private static $api_access = [ 'view' => [ 'CalculatedTotal', 'Sort', 'GroupSort', 'TableTitle', 'TableSubTitleNOHTML', 'CartTitle', 'CartSubTitle', 'Order', ], ]; /** * Standard SS variable. * * @var string */ private static $table_name = 'OrderAttribute'; private static $db = [ 'CalculatedTotal' => 'Currency', 'Sort' => 'Int', 'GroupSort' => 'Int', ]; /** * Standard SS variable. * * @var array */ private static $has_one = [ 'Order' => Order::class, ]; /** * Standard SS variable. * * @var array */ private static $casting = [ 'TableTitle' => 'HTMLText', 'TableSubTitle' => 'HTMLText', 'TableSubTitleNOHTML' => 'Text', 'CartTitle' => 'HTMLText', 'CartSubTitle' => 'HTMLText', 'CalculatedTotalAsMoney' => 'Money', ]; /** * Standard SS variable. * * @var array */ private static $default_sort = [ 'OrderAttribute.GroupSort' => 'ASC', 'OrderAttribute.Sort' => 'ASC', 'OrderAttribute.ID' => 'ASC', ]; /** * Standard SS variable. * * @var array */ private static $indexes = [ 'GroupSort' => true, 'Sort' => true, 'ID' => true, ]; /** * Standard SS variable. * * @var string */ private static $singular_name = 'Order Entry'; /** * Standard SS variable. * * @var string */ private static $plural_name = 'Order Extra Descriptions'; /** * Standard SS variable. * * @var string */ private static $description = 'Any item that is added to the order - be it before (e.g. product) or after the subtotal (e.g. tax).'; /** * Helps in speeding up code. * This can be a static variable as it is the same for all OrderItems for an Order. * * @var array */ private static $_price_has_been_fixed = []; public function i18n_singular_name() { return _t('OrderAttribute.ORDERENTRY', 'Order Entry'); } public function i18n_plural_name() { return _t('OrderAttribute.ORDERENTRIES', 'Order Entries'); } /** * extended in OrderModifier and OrderItem * Starts up the order Atribute * TODO: introduce system like we have for Controller * which makes sure that all parent init methods are called. */ public function init() { return true; } /** * standard SS method. * * @param \SilverStripe\Security\Member $member * @param mixed $context * * @return bool */ public function canCreate($member = null, $context = []) { if (! $member) { $member = Security::getCurrentUser(); } $extended = $this->extendedCan(__FUNCTION__, $member); if (null !== $extended) { return $extended; } if (Permission::checkMember($member, Config::inst()->get(EcommerceRole::class, 'admin_permission_code'))) { return true; } return parent::canEdit($member); } /** * Standard SS method * This is an important method. * * @param \SilverStripe\Security\Member $member * * @return bool */ public function canView($member = null) { if (! $member) { $member = Security::getCurrentUser(); } $extended = $this->extendedCan(__FUNCTION__, $member); if (null !== $extended) { return $extended; } if (! $this->exists()) { return true; } if (null === $this->_canView) { $this->_canView = false; if ($this->OrderID) { $o = $this->getOrderCached(); if ($o) { if ($o->exists()) { if ($o->canView($member)) { $this->_canView = true; } } } } } return $this->_canView; } /** * Standard SS method * This is an important method. * * @param \SilverStripe\Security\Member $member * * @return bool */ public function canEdit($member = null) { if (! $member) { $member = Security::getCurrentUser(); } $extended = $this->extendedCan(__FUNCTION__, $member); if (null !== $extended) { return $extended; } if (! $this->exists()) { return true; } if (null === $this->_canEdit) { $this->_canEdit = ! $this->priceHasBeenFixed(); } return $this->_canEdit; } /** * Standard SS method. * * @param \SilverStripe\Security\Member $member * * @return bool */ public function canDelete($member = null) { return false; } /** * link to edit the record. * * @param null|string $action - e.g. edit * * @return string */ public function CMSEditLink($action = null) { return CMSEditLinkAPI::find_edit_link_for_object($this, $action); } /** * @param int $orderID * @param bool $value */ public static function set_price_has_been_fixed(?int $orderID = 0, $value = false) { $orderID = ShoppingCart::current_order_id($orderID); self::$_price_has_been_fixed[$orderID] = $value; } /** * @param int $orderID * * @return null|bool */ public static function get_price_has_been_fixed(?int $orderID = 0) { $orderID = ShoppingCart::current_order_id($orderID); return isset(self::$_price_has_been_fixed[$orderID]) ? self::$_price_has_been_fixed[$orderID] : null; } //##################### //# TEMPLATE METHODS ## //##################### /** * This is a key function that returns the type of the * object. In principle anything can be returned * but the intention is to only return a few options * e.g. OrderItem, Tax, Delivery, etc... so that * computations can be carried out based on the type of * OrderAttribute we are looking at. * It also allows to get a group of Order Attributes that * contains both modifiers and orderItems. * * @return string */ public function OrderAttributeType() { return $this->ClassName; } /** * returns the order - for some unknown reason it seems we need this. * * @return null|Order */ public function Order() { return Order::get_order_cached((int) $this->OrderID); } /** * Return a string of class names, in order * of hierarchy from OrderAttribute for the * current attribute. * * e.g.: "product_orderitem orderitem * orderattribute". * * Used by the templates and for ajax updating functionality. * * @return string */ public function Classes() { $class = static::class; $classes = []; $class = get_parent_class($class); while ($class && DataObject::class !== $class) { $classes[] = strtolower(ClassInfo::shortName($class)); $class = get_parent_class($class); } if (is_a($this, EcommerceConfigClassNames::getName(OrderItem::class))) { $classes[] = strtolower($this->BuyableClassName); } return implode(' ', $classes); } /** * returns the instance of EcommerceConfigAjax for use in templates. * In templates, it is used like this: * $EcommerceConfigAjax.TableID. * * @return EcommerceConfigAjaxDefinitions */ public function AJAXDefinitions() { return EcommerceConfigAjax::get_one($this); } /* * Should this item be shown on check out page table? * @return bool */ public function ShowInTable(): bool { return true; } /** *Should this item be shown on in the cart (which is on other pages than the checkout page). * * @return bool */ public function ShowInCart() { return $this->ShowInTable(); } /** * Return a name of what this attribute is * called e.g. "Product 21" or "Discount". * * @return string */ public function TableTitle() { return $this->getTableTitle(); } public function getTableTitle() { return $this->i18n_singular_name(); } /** * Return a name of what this attribute is * called e.g. "Product 21" or "Discount" * Cart is a short version of table. * * @return string */ public function CartTitle() { return $this->getCartTitle(); } public function getCartTitle() { return $this->TableTitle(); } /** * the sub title for the order item or order modifier. * * @return string */ public function TableSubTitle() { return $this->getTableSubTitle(); } public function getTableSubTitle() { return ''; } /** * the sub title for the order item or order modifier. * * @return string */ public function TableSubTitleNOHTML() { return $this->getTableSubTitleNOHTML(); } public function getTableSubTitleNOHTML() { return str_replace("\n", '', strip_tags($this->getTableSubTitle())); } /** * the sub title for the order item or order modifier. * Cart is a short version of table. * * @return string */ public function CartSubTitle() { return $this->getCartSubTitle(); } public function getCartSubTitle() { return $this->TableSubTitle(); } /** * Returns the Money object of the CalculatedTotal. * * @return \SilverStripe\ORM\FieldType\DBMoney */ public function CalculatedTotalAsMoney() { return $this->getCalculatedTotalAsMoney(); } public function getCalculatedTotalAsMoney() { return EcommerceCurrency::get_money_object_from_order_currency($this->CalculatedTotal, $this->getOrderCached()); } public function runUpdate($force = false) { $this->baseRunUpdateCalled = true; } /** * Debug helper method. * Access through : /shoppingcart/debug/. */ public function debug() { return EcommerceTaskDebugCart::debug_object($this); } /** * Standard SS method * We add the Sort value from the OrderAttributeGroup to the OrderAttribute. */ protected function onBeforeWrite() { parent::onBeforeWrite(); if ($this->OrderAttributeGroupID) { $group = $this->OrderAttributeGroup(); if ($group) { $this->GroupSort = $group->Sort; } } } /** * Standard SS method. */ protected function onAfterWrite() { parent::onAfterWrite(); //crucial! Order::set_needs_recalculating(true, $this->OrderID); } /** * @description - tells you if an order item price has been "fixed" * meaning that is has been saved in the CalculatedTotal field so that * it can not be altered. * * Default returns false; this is good for uncompleted orders * but not so good for completed ones. * * We use direct calls to self::$_price_has_been_fixed to make the code simpler and faster. * * @param mixed $recalculate * * @return bool */ protected function priceHasBeenFixed($recalculate = false) { if (null === self::get_price_has_been_fixed($this->OrderID) || $recalculate) { self::$_price_has_been_fixed[$this->OrderID] = false; $order = $this->getOrderCached(); if ($order) { if ($order->IsSubmitted()) { self::$_price_has_been_fixed[$this->OrderID] = true; if ($recalculate) { user_error('You are trying to recalculate an order that is already submitted.', E_USER_NOTICE); } } } } return self::$_price_has_been_fixed[$this->OrderID]; } } |