Provides a means for specifying many variations on a product.
Used in combination with ProductAttributes, such as color, size.
A variation will specify one particular combination, such as red, and large.
public function actionGetVariations() { if (Yii::app()->request->isAjaxRequest && isset($_POST['product'])) { $product = Products::model()->findByPk($_POST['product']); echo CHtml::hiddenField('product_id', $product->product_id); if ($variations = $product->getVariations()) { foreach ($variations as $variation) { $field = "Variations[{$variation[0]->specification_id}][]"; echo '<div class="shop-variation-element">'; echo '<strong>' . CHtml::label($variation[0]->specification->title . '</strong>', $field, array('class' => 'lbl-header')); if ($variation[0]->specification->required) { echo ' <span class="required">*</span>'; } echo '<br />'; if ($variation[0]->specification->input_type == 'textfield') { echo CHtml::textField($field); } else { if ($variation[0]->specification->input_type == 'select') { // If the specification is required, preselect the first field. // Otherwise let the customer choose which one to pick // $product->variationCount > 1 ? true : false means, that the // widget should display the _absolute_ price if only 1 variation // is available, otherwise the relative (+ X $) echo CHtml::radioButtonList($field, $variation[0]->specification->required ? $variation[0]->id : null, ProductVariation::listData($variation, $product->variationCount > 1 ? true : false), array('template' => '{input} {label}', 'separator' => '<div class="clear"></div>')); } } echo '</div>'; } } } else { throw new CHttpException(404); } }
function getSpecifications($position) { $string = '<table class="specifications">'; foreach ($position->getSpecifications() as $key => $specification) { if ($model = ProductSpecification::model()->findByPk($key)) { if ($model->input_type == 'textfield') { $title = $model->title; $value = $specification[0]; } else { $title = $model->title; $productvariation = ProductVariation::model()->findByPk($specification[0]); if ($productvariation) { $value = $productvariation->title; } else { $value = ''; } } } else { if ($key == 'image') { $title = Shop::t('Filename'); $value = $specification; } } $string .= sprintf('<tr><td>%s</td><td>%s</td></tr>', @$title, @$value); } $string .= '</table>'; return $string; }
public function testZeroPriceWithVariations() { Config::inst()->update('ProductCategory', 'must_have_price', true); $products = $this->electronics->ProductsShowable(); $this->assertEquals(0, $products->count(), 'No product should be returned as there\'s no price set'); // Create a variation for HDTV ProductVariation::create(array('InternalItemID' => '50-Inch', 'Price' => 1200, 'ProductID' => $this->hdtv->ID))->write(); $products = $this->electronics->ProductsShowable(); $this->assertDOSEquals(array(array('URLSegment' => 'hdtv')), $products, 'HDTV has a priced extension and should now show up in the list of products'); }
public function getPrice() { $price = $this->product->price; if ($this->specifications) { foreach ($this->getSpecifications() as $key => $spec) { $price += @ProductVariation::model()->findByPk(@$spec[0])->price_adjustion; } } return $this->amount * $price; }
public function testVariationOrderItem() { $cart = ShoppingCart::singleton(); //config ProductVariation::config()->title_has_label = true; ProductVariation::config()->title_separator = ':'; ProductVariation::config()->title_glue = ', '; $emptyitem = $this->redlarge->Item(); $this->assertEquals(1, $emptyitem->Quantity, "Items always have a quantity of at least 1."); $cart->add($this->redlarge); $item = $cart->get($this->redlarge); $this->assertTrue((bool) $item, "item exists"); $this->assertEquals(1, $item->Quantity); $this->assertEquals(22, $item->UnitPrice()); $this->assertEquals("Size:Large, Color:Red", $item->SubTitle()); }
public function save() { ActiveRecordModel::beginTransaction(); $parent = Product::getInstanceByID($this->request->get('id'), true); $items = json_decode($this->request->get('items'), true); $types = json_decode($this->request->get('types'), true); $variations = json_decode($this->request->get('variations'), true); $existingTypes = $existingVariations = $existingItems = array(); $currency = $this->application->getDefaultCurrencyCode(); // deleted types foreach ($types as $id) { if (is_numeric($id)) { $existingTypes[] = $id; } } $parent->deleteRelatedRecordSet('ProductVariationType', new ARDeleteFilter(new NotINCond(new ARFieldHandle('ProductVariationType', 'ID'), $existingTypes))); // deleted variations foreach ($variations as $type => $typeVars) { foreach ($typeVars as $id) { if (is_numeric($id)) { $existingVariations[] = $id; } } } $f = new ARDeleteFilter(new INCond(new ARFieldHandle('ProductVariation', 'typeID'), $existingTypes)); $f->mergeCondition(new NotINCond(new ARFieldHandle('ProductVariation', 'ID'), $existingVariations)); ActiveRecordModel::deleteRecordSet('ProductVariation', $f); // deleted items foreach ($items as $id) { if (is_numeric($id)) { $existingItems[] = $id; } } $parent->deleteRelatedRecordSet('Product', new ARDeleteFilter(new NotINCond(new ARFieldHandle('Product', 'ID'), $existingItems))); // load existing records foreach (array('Types' => 'ProductVariationType', 'Variations' => 'ProductVariation', 'Items' => 'Product') as $arr => $class) { $var = 'existing' . $arr; $array = ${$var}; if ($array) { ActiveRecordModel::getRecordSet($class, new ARSelectFilter(new INCond(new ARFieldHandle($class, 'ID'), $array))); } } $idMap = array(); // save types $request = $this->request->toArray(); foreach ($types as $index => $id) { if (!is_numeric($id)) { $type = ProductVariationType::getNewInstance($parent); $idMap[$id] = $type; } else { $type = ActiveRecordModel::getInstanceByID('ProductVariationType', $id); } $type->setValueByLang('name', null, $request['variationType'][$index]); $type->position->set($index); if (!empty($request['typeLang_' . $id])) { foreach ($request['typeLang_' . $id] as $field => $value) { list($field, $lang) = explode('_', $field, 2); $type->setValueByLang($field, $lang, $value); } } $type->save(); } // save variations $tree = array(); $typeIndex = -1; foreach ($variations as $typeID => $typeVars) { $type = is_numeric($typeID) ? ActiveRecordModel::getInstanceByID('ProductVariationType', $typeID) : $idMap[$typeID]; $typeIndex++; foreach ($typeVars as $index => $id) { if (!is_numeric($id)) { $variation = ProductVariation::getNewInstance($type); $idMap[$id] = $variation; } else { $variation = ActiveRecordModel::getInstanceByID('ProductVariation', $id); } $variation->position->set($index); $variation->setValueByLang('name', null, $request['variation'][$id]); if (!empty($request['variationLang_' . $id])) { foreach ($request['variationLang_' . $id] as $field => $value) { list($field, $lang) = explode('_', $field, 2); $variation->setValueByLang($field, $lang, $value); } } $variation->save(); $tree[$typeIndex][] = $variation; } } $images = array(); // save items foreach ($items as $index => $id) { if (!is_numeric($id)) { $item = $parent->createChildProduct(); $idMap[$id] = $item; } else { $item = ActiveRecordModel::getInstanceByID('Product', $id); } $item->isEnabled->set(!empty($request['isEnabled'][$id])); if (!$request['sku'][$index]) { $request['sku'][$index] = $item->sku->get(); } foreach (array('sku', 'stockCount', 'shippingWeight') as $field) { if ($item->{$field}->get() || $request[$field][$index]) { $item->{$field}->set($request[$field][$index]); } } $item->setChildSetting('weight', $request['shippingWeightType'][$index]); $item->setChildSetting('price', $request['priceType'][$index]); if (!strlen($request['priceType'][$index])) { $request['price'][$index] = ''; } $item->setPrice($currency, $request['price'][$index]); $item->save(); // assign variations $currentVariationValues = $currentVariations = array(); foreach ($item->getRelatedRecordSet('ProductVariationValue') as $variationValue) { $currentVariations[$variationValue->variation->get()->getID()] = $variationValue->variation->get(); $currentVariationValues[$variationValue->variation->get()->getID()] = $variationValue; } foreach ($this->getItemVariations($tree, $index) as $variation) { if (!isset($currentVariations[$variation->getID()])) { ProductVariationValue::getNewInstance($item, $variation)->save(); } unset($currentVariations[$variation->getID()]); } foreach ($currentVariations as $deletedVariation) { $currentVariationValues[$deletedVariation->getID()]->delete(); } // set image if ($_FILES['image']['tmp_name'][$index]) { if ($item->defaultImage->get()) { $item->defaultImage->get()->load(); $image = $item->defaultImage->get(); } else { $image = ProductImage::getNewInstance($item); } $image->save(); $image->setFile($_FILES['image']['tmp_name'][$index]); $image->save(); $images[$item->getID()] = $image->toArray(); unset($images[$item->getID()]['Product']); } } ActiveRecordModel::commit(); // pass ID's for newly created records $ids = array(); foreach ($idMap as $id => $instance) { $ids[$id] = $instance->getID(); } $response = new ActionResponse('ids', $ids); $response->set('parent', $parent->getID()); $response->set('images', $images); $response->set('variationCount', $parent->getRelatedRecordCount('Product', new ARSelectFilter(new EqualsCond(new ARFieldHandle('Product', 'isEnabled'), true)))); return $response; }
//var_dump($products);die(); foreach ($products as $position => $product) { if ($model = Products::model()->findByPk($product['product_id'])) { $variations = ''; if (isset($product['Variations'])) { foreach ($product['Variations'] as $specification => $variation) { if ($specification = ProductSpecification::model()->findByPk($specification)) { if ($specification->input_type == 'textfield') { $variation = $variation[0]; } else { $variation = ProductVariation::model()->findByPk($variation); } if (Shop::module()->allowPositionLiveChange) { if ($specification->input_type == 'select') { $name = sprintf('variation_%s_%s', $position, $specification->id); $variations .= CHtml::radioButtonList($name, $variation->id, ProductVariation::listData($variation->getVariations(), true)); Yii::app()->clientScript->registerScript($name, "\r\n\t\t\t\t\t\t\t\t\t\t\$('[name=\"" . $name . "\"]').click(function(){\r\n\t\t\t\t\t\t\t\t\t\$.ajax({\r\n\t\t\t\t\t\t\t\t\t\t\t'url' : '" . CController::createUrl('//shop/shoppingCart/updateVariation') . "',\r\n\t\t\t\t\t\t\t\t\t\t\t'type' : 'POST',\r\n\t\t\t\t\t\t\t\t\t\t\t'data' : \$(this),\r\n\t\t\t\t\t\t\t\t\t\t\terror: function() {\r\n\t\t\t\t\t\t\t\t\t\t\t\$('#amount_" . $position . "').css('background-color', 'red');\r\n\t\t\t\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\t\t\t\tsuccess: function(result) {\r\n\t\t\t\t\t\t\t\t\t\t\t\$('.amount_" . $position . "').css('background-color', 'lightgreen');\r\n\t\t\t\t\t\t\t\t\t\t\t\$('.widget_amount_" . $position . "').css('background-color', 'lightgreen');\r\n\t\t\t\t\t\t\t\t\t\t\t\$('.widget_amount_" . $position . "').html(\$('.amount_" . $position . "').val());\r\n\t\t\t\t\t\t\t\t\t\t\t\$('.price_" . $position . "').html(result);\t\r\n\t\t\t\t\t\t\t\t\t\t\t\$('.price_single_" . $position . "').load('" . $this->createUrl('//shop/shoppingCart/getPriceSingle?position=' . $position) . "');\r\n\t\t\t\t\t\t\t\t\t\t\t\$('.price_total').load('" . $this->createUrl('//shop/shoppingCart/getPriceTotal') . "');\r\n\t\t\t\t\t\t\t\t\t\t\t\$('.shipping_costs').load('" . $this->createUrl('//shop/shoppingCart/getShippingCosts') . "');\r\n\r\n\t\t\t\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\t\t\t\t\$('input:checked').trigger('click');\r\n\t\t\t\t\t\t\t\t\t\t"); $variations .= '<br />'; } } else { $variations .= $specification . ': ' . $variation . '<br />'; } } $img = CHtml::image(Yii::app()->baseUrl . '/' . $variation, '', array('width' => Shop::module()->imageWidthThumb)); } } printf('<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td class="text-right price_single_' . $position . '">%s</td><td class="text-right price_' . $position . '">%s</td><td>%s</td></tr>', $img, CHtml::textField('amount_' . $position, $product['amount'], array('size' => 4, 'class' => 'amount_' . $position)), $model->title, $variations, Shop::priceFormat($model->getPrice($product['Variations'])), Shop::priceFormat($model->getPrice($product['Variations'], $product['amount'])), CHtml::link(Shop::t('Remove'), array('//shop/shoppingCart/delete', 'id' => $position), array('confirm' => Shop::t('Are you sure?')))); Yii::app()->clientScript->registerScript('amount_' . $position, "\r\n\t\t\t\t\t\$('.amount_" . $position . "').keyup(function() {\r\n\t\t\t\t\t\t\$.ajax({\r\n\t\t\t\t\t\t\turl:'" . $this->createUrl('//shop/shoppingCart/updateAmount') . "',\r\n\t\t\t\t\t\t\tdata: \$('#amount_" . $position . "'),\r\n\t\t\t\t\t\t\tsuccess: function(result) {\r\n\t\t\t\t\t\t\t\$('.amount_" . $position . "').css('background-color', 'lightgreen');\r\n\t\t\t\t\t\t\t\$('.widget_amount_" . $position . "').css('background-color', 'lightgreen');\r\n\t\t\t\t\t\t\t\$('.widget_amount_" . $position . "').html(\$('.amount_" . $position . "').val());\r\n\t\t\t\t\t\t\t\$('.price_" . $position . "').html(result);\t\r\n\t\t\t\t\t\t\t\$('.price_total').load('" . $this->createUrl('//shop/shoppingCart/getPriceTotal') . "');\r\n\t\t\t\t\t\t\t\$('.shipping_costs').load('" . $this->createUrl('//shop/shoppingCart/getShippingCosts') . "');\r\n\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\terror: function() {\r\n\t\t\t\t\t\t\t\$('#amount_" . $position . "').css('background-color', 'red');\r\n\t\t\t\t\t\t\t},\r\n\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t\t\t"); } } if ($shippingMethod = Shop::getShippingMethod()) {
/** * Обновляем информацию о наличии товаров на складе * @param array $one - один товар * @param string $storehouseGuid - GUID склада в 1С откуда получаем остатки */ public function updateProductAvailability($one, $orderCarrierGuid, $storehouseGuid) { //проверяем документ "Перемещение Товаров" или "Приходный Ордер На Товары" $docProduct = $one['@attributes']['type'] == "StandardODATA.Document_ПеремещениеТоваров_Товары_RowType" ? ['type' => false, 'docName' => 'Перемещение Товаров'] : ['type' => true, 'docName' => 'Приходный Ордер На Товары']; $pvar = ProductVariation::model()->find('id_1c = :id_1c', [':id_1c' => $one['d:Номенклатура_Key']]); if (!$pvar) { $this->log1c("При обработке документа '" . $docProduct['docName'] . "', не найден товар с id_1c = {" . $one['d:Ref_Key'] . "}"); continue; } // count balance for pvar $pvarBalance = app()->to1c->productBalance($one['d:Номенклатура_Key'], $one['d:Характеристика_Key'], $orderCarrierGuid, $storehouseGuid); /** * уменьшаем баланс если документ является Перемещением Товаров * прибавляем баланс если документ является Приходным Ордером На Товары */ $in_stock = $pvar->in_stock + ($docProduct['type'] ? (int) $pvarBalance : -(int) $pvarBalance); //update balance in product variation $pvar->edit(['in_stock' => $in_stock], false); // count balance for product $productBalance = $pvar->bproduct->countBalance(); $pvar->bproduct->edit(['in_stock' => $productBalance], false); }
/** * finds similar ("siblings") variations where one * attribute value is NOT the same. * * @return DataList */ public function MostLikeMe() { $idArray = array(); foreach ($this->AttributeValues() as $excludeValue) { unset($getAnyArray); $getAnyArray = array(); foreach ($this->AttributeValues() as $innerValue) { if ($excludeValue->ID != $innerValue->ID) { $getAnyArray[$innerValue->ID] = $innerValue->ID; } //find a product variation that has the getAnyArray Values $items = ProductVariation::get()->innerJoin("ProductVariation_AttributeValues", "\"ProductVariation\".\"ID\" = \"ProductVariationID\" ")->filter(array("ProductAttributeValueID" => $getAnyArray, "ProductID" => $this->ProductID))->exclude(array("ID" => $this->ID)); $idArray += $items->map("ID", "ID")->toArray(); } } return ProductVariation::get()->filter(array("ID" => $idArray)); }
public function registerVariation(ProductVariation $variation) { $this->variations[$variation->getID()] = $variation; }
/** * returns the matching variation if any * @param array $attributes formatted as (TypeID => ValueID, TypeID => ValueID) * * @return ProductVariation | NULL */ function getVariationByAttributes(array $attributes) { if (!is_array($attributes) || !count($attributes)) { user_error("attributes must be provided as an array of numeric keys and values IDs...", E_USER_NOTICE); return null; } $variations = ProductVariation::get()->filter(array("ProductID" => $this->owner->ID)); $keyattributes = array_keys($attributes); $id = $keyattributes[0]; foreach ($attributes as $typeid => $valueid) { if (!is_numeric($typeid) || !is_numeric($valueid)) { user_error("key and value ID must be numeric", E_USER_NOTICE); return null; } $alias = "A{$typeid}"; $variations = $variations->where("\"{$alias}\".\"ProductAttributeValueID\" = {$valueid}")->innerJoin("ProductVariation_AttributeValues", "\"ProductVariation\".\"ID\" = \"{$alias}\".\"ProductVariationID\"", $alias); } if ($variation = $variations->First()) { return $variation; } return null; }
foreach ($variations as $variation) { $i++; $field = "Variations[{$variation[0]->specification_id}][]"; echo '<div class="product_variation product_variation_' . $i . '">'; echo CHtml::label($variation[0]->specification->title, $field, array('class' => 'lbl-header')); if ($variation[0]->specification->required) { echo ' <span class="required">*</span>'; } echo '<br />'; if ($variation[0]->specification->input_type == 'textfield') { echo CHtml::textField($field); } else { if ($variation[0]->specification->input_type == 'select') { // If the specification is required, preselect the first field. Otherwise // let the customer choose which one to pick echo CHtml::radioButtonList($field, $variation[0]->specification->required ? $variation[0]->id : null, ProductVariation::listData($variation)); } else { if ($variation[0]->specification->input_type == 'image') { echo CHtml::fileField($field); } } } echo '</div>'; if ($i % 2 == 0) { echo '<div style="clear: both;"></div>'; } } } echo '<div style="clear: both;"></div>'; echo '<br />'; echo CHtml::hiddenField('product_id', $model->product_id);
public function getPrice($variations = null, $amount = 1) { if ($this->price === null) { $price = (double) Shop::module()->defaultPrice; } else { $price = (double) $this->price; } if ($this->tax) { $price *= $this->tax->percent / 100 + 1; } if ($variations) { foreach ($variations as $key => $variation) { if (is_numeric($variation)) { $price += @ProductVariation::model()->findByPk($variation)->getPriceAdjustion(); } } } return (double) ($price *= $amount); }
public function getVariations() { return ProductVariation::model()->findAll('product_id = :pid and specification_id = :sid ', array(':pid' => $this->product_id, ':sid' => $this->specification_id)); }
function resaveAllPRoductsVariations_210() { $explanation = "\r\n\t\t\t<h1>210. Resave All Product Variations to update the FullName and FullSiteTreeSort Field</h1>\r\n\t\t\t<p>Saves all the product variations on the site. You may need to run this task several times.</p>\r\n\t\t"; if ($this->retrieveInfoOnly) { return $explanation; } else { echo $explanation; } $count = 0; if (class_exists("ProductVariation")) { ProductVariation::get()->where("\"FullName\" = '' OR \"FullName\" IS NULL")->sort("ID", "ASC")->limit($this->limit, $this->start); if ($variations->count()) { foreach ($variations as $variation) { $count++; $variation->write(); $this->DBAlterationMessageNow("Saving Variation " . $variation->getTitle()); } return $this->start + $this->limit; } else { $this->DBAlterationMessageNow("No product variations to update."); } } else { $this->DBAlterationMessageNow("There are not ProductVariations in this project"); } return 0; }
/** * Conditions for whether a product can be purchased: * - global allow purchase is enabled * - product AllowPurchase field is true * - if variations, then one of them needs to be purchasable * - if not variations, selling price must be above 0 * * Other conditions may be added by decorating with the canPurchase function * * @param Member $member * @param int $quantity * * @return boolean */ public function canPurchase($member = null, $quantity = 1) { $global = self::config()->global_allow_purchase; if (!$global || !$this->AllowPurchase) { return false; } $allowpurchase = false; $extension = self::has_extension("ProductVariationsExtension"); if ($extension && ProductVariation::get()->filter("ProductID", $this->ID)->first()) { foreach ($this->Variations() as $variation) { if ($variation->canPurchase($member, $quantity)) { $allowpurchase = true; break; } } } else { $allowpurchase = $this->sellingPrice() > 0 || self::config()->allow_zero_price; } // Standard mechanism for accepting permission changes from decorators $permissions = $this->extend('canPurchase', $member, $quantity); $permissions[] = $allowpurchase; return min($permissions); }
private function addspecialprice() { $task = new EcommerceTaskCreateMemberGroups(); $task->run(false); $customerGroup = EcommerceRole::get_customer_group(); if (!$customerGroup) { die("could not create customer group"); } $group = new Group(); $group->Title = "Discount Customers"; $group->Code = "discountcustomers"; $group->ParentID = $customerGroup->ID; $group->write(); $member = new Member(); $member->FirstName = 'Bob'; $member->Surname = 'Jones'; $member->Email = '*****@*****.**'; $member->Password = '******'; $member->write(); $member->Groups()->add($group); $products = Product::get()->where("ClassName = 'Product'")->sort("RAND()")->limit(2); $this->addExamplePages(4, "Special price for particular customers", $products); $i = 0; foreach ($products as $product) { $i++; $complexObjectPrice = new ComplexPriceObject(); if ($i == 1) { $complexObjectPrice->Price = $product->Price - 1.5; } elseif ($i == 2) { $complexObjectPrice->Percentage = 10; $complexObjectPrice->Reduction = 2.5; } else { $complexObjectPrice->Price = $product->Price - 1.5; $complexObjectPrice->Percentage = 10; $complexObjectPrice->Reduction = 2.5; } $complexObjectPrice->From = date("Y-m-d h:n:s", strtotime("now")); $complexObjectPrice->Until = date("Y-m-d h:n:s", strtotime("next year")); $complexObjectPrice->ProductID = $product->ID; $complexObjectPrice->write(); $complexObjectPrice->Groups()->add($group); $product->Content = "<p><a href=\"Security/login/?BackURL=" . $product->Link() . "\">Login</a> as bob@silverstripe-ecommerce.com, password: test123 to get a special price. You can then <a href=\"Security/logout/?BackURL=" . $product->Link() . "\">log out</a> again to see the original price.</p>"; $this->addToTitle($product, "member price", true); } $variations = ProductVariation::get()->where("ClassName = 'ProductVariation'")->sort("RAND()")->limit(2); $i = 0; foreach ($variations as $variation) { $i++; $complexObjectPrice = new ComplexPriceObject(); if ($i == 1) { $complexObjectPrice->Price = $product->Price - 1.5; } elseif ($i == 2) { $complexObjectPrice->Percentage = 10; $complexObjectPrice->Reduction = 2.5; } else { $complexObjectPrice->Price = $product->Price - 1.5; $complexObjectPrice->Percentage = 10; $complexObjectPrice->Reduction = 2.5; } $complexObjectPrice->Price = $variation->Price - 1.5; $complexObjectPrice->From = date("Y-m-d h:n:s", strtotime("now")); $complexObjectPrice->Until = date("Y-m-d h:n:s", strtotime("next year")); $complexObjectPrice->ProductVariationID = $variation->ID; $complexObjectPrice->write(); $complexObjectPrice->Groups()->add($group); $product = $variation->Product(); $this->addExamplePages(4, "Special price for particular customers for product variations {$i}", $product); $product->Content = "<p><a href=\"Security/login/?BackURL=" . $product->Link() . "\">Login</a> as bob@jones.com, password: test123 to get a special price</p>"; $this->addToTitle($product, "member price", true); } }
/** * TO DO: work out how it works... * */ function generateVariationsFromAttributeValues(array $values) { $cpt = 0; $variations = array(); foreach ($values as $typeID => $typeValues) { $this->owner->addAttributeType($typeID); $copyVariations = $variations; $variations = array(); foreach ($typeValues as $value) { $value = array($value); if (count($copyVariations) > 0) { foreach ($copyVariations as $variation) { $variations[] = array_merge($variation, $value); } } else { $variations[] = $value; } } } foreach ($variations as $variation) { sort($variation); $str = implode(',', $variation); $add = true; $productVariationIDs = DB::query("SELECT \"ID\" FROM \"ProductVariation\" WHERE \"ProductID\" = '{$this->owner->ID}'")->column(); if (count($productVariationIDs) > 0) { $productVariationIDs = implode(',', $productVariationIDs); $variationValues = DB::query("SELECT GROUP_CONCAT(\"ProductAttributeValueID\" ORDER BY \"ProductAttributeValueID\" SEPARATOR ',') FROM \"ProductVariation_AttributeValues\" WHERE \"ProductVariationID\" IN ({$productVariationIDs}) GROUP BY \"ProductVariationID\"")->column(); if (in_array($str, $variationValues)) { $add = false; } } if ($add) { $cpt++; $newVariation = new ProductVariation(array('ProductID' => $this->owner->ID, 'Price' => $this->owner->Price)); $newVariation->write(); $newVariation->AttributeValues()->addMany($variation); } } return $cpt; }
private function importProductVariationValue(Product $product, $index, $name) { $parent = $product->parent->get(); $type = $this->getVariationTypeByIndex($parent, $index); if (!$type->getID()) { $type = $this->importVariationType($parent, $index, ''); } $f = new ARSelectFilter(); $f->mergeCondition(new EqualsCond(MultiLingualObject::getLangSearchHandle(new ARFieldHandle('ProductVariation', 'name'), $this->application->getDefaultLanguageCode()), $name)); $values = $type->getRelatedRecordSet('ProductVariation', $f); if ($values->size()) { $variation = $values->get(0); } else { $variation = ProductVariation::getNewInstance($type); $variation->setValueByLang('name', null, $name); $variation->save(); } if (!$product->getID()) { $product->save(); } $f = new ARDeleteFilter(new EqualsCond(new ARFieldHandle('ProductVariation', 'typeID'), $type->getID())); $product->deleteRelatedRecordSet('ProductVariationValue', $f, array('ProductVariation')); ProductVariationValue::getNewInstance($product, $variation)->save(); }
function ProductVariationGetPluralName() { return Convert::raw2att(ProductVariation::get_plural_name()); }
public function getPrice($variations = null, $amount = 1) { $price = (double) $this->price; if ($variations) { foreach ($variations as $key => $variation) { $price += @ProductVariation::model()->findByPk($variation[0])->price_adjustion; } } (double) ($price *= $amount); return $price; }
function variationRow(&$obj, $val, $record) { $obj->write(); //make sure product is in DB //TODO: or find existing variation $variation = DataObject::get_one('ProductVariation', "InternalItemID = '{$val}'"); if (!$variation) { $variation = new ProductVariation(); $variation->InternalItemID = $val; $variation->ProductID = $obj->ID; //link to product $variation->write(); } $varcols = array('->processVariation', '->processVariation1', '->processVariation2', '->processVariation3', '->processVariation4', '->processVariation5', '->processVariation6'); foreach ($varcols as $col) { if (isset($record[$col])) { $parts = explode(":", $record[$col]); if (count($parts) == 2) { $attributetype = trim($parts[0]); $attributevalues = explode(",", $parts[1]); //get rid of empty values foreach ($attributevalues as $key => $value) { if (!$value || trim($value) == "") { unset($attributevalues[$key]); } } if (count($attributevalues) == 1) { $attributetype = ProductAttributeType::find_or_make($attributetype); foreach ($attributevalues as $key => $value) { $val = trim($value); if ($val != "" && $val != null) { $attributevalues[$key] = $val; } //remove outside spaces from values } $attributetype->addValues($attributevalues); //create and add values to attribute type $obj->VariationAttributes()->add($attributetype); //add variation attribute type to product //TODO: if existing variation, then remove current values //record vairation attribute values (variation1, 2 etc) foreach ($attributetype->convertArrayToValues($attributevalues) as $value) { $variation->AttributeValues()->add($value); break; } } } } } //copy db values into variation (InternalItemID, Price, Stock, etc) ...there will be unknowns from extensions. $dbfields = $variation->db(); foreach ($record as $field => $value) { if (isset($dbfields[$field])) { $variation->{$field} = $value; } } $variation->write(); }
public static function set_current_style_option_code($v) { self::$current_style_option_code = $v; }
function run($request) { $productVariationArrayID = array(); if (empty($_GET["silent"])) { $this->verbose = true; } else { $this->verbose = intval($_GET["silent"]) == 1 ? false : true; } if (empty($_GET["productid"])) { $productID = 0; } elseif ($_GET["productid"] == 'all') { $productID = -1; } else { $productID = intval($_GET["productid"]); } if (empty($_GET["live"])) { $live = false; } else { $live = intval($_GET["live"]) == 1 ? true : false; } if ($live) { if ($this->verbose) { DB::alteration_message("this is a live task", "deleted"); } } else { if ($this->verbose) { DB::alteration_message("this is a test only. If you add a live=1 get variable then you can make it for real ;-)", "created"); } } if ($productID == -1) { $products = Product::get(); } else { $products = null; $product = Product::get()->byID($productID); if ($product) { $products = new ArrayList(); $products->push($product); } } if ($products && $products->count()) { foreach ($products as $product) { $productID = $product->ID; if ($products->count()) { if ($this->verbose) { DB::alteration_message("Deleting variations for " . $product->Title, "deleted"); } $variations = ProductVariation::get()->filter(array("ProductID" => $productID))->limit(100); if ($variations->count()) { if ($this->verbose) { DB::alteration_message("PRE DELETE COUNT: " . $variations->count()); } foreach ($variations as $variation) { if ($this->verbose) { DB::alteration_message(" Deleting Variation: " . $variation->Title(), "deleted"); } if ($live) { $variation->delete(); } $productVariationArrayID[$variation->ID] = $variation->ID; } $variations = ProductVariation::get()->filter(array("ProductID" => $productID))->limit(100); if ($live) { if ($variations->count()) { if ($this->verbose) { DB::alteration_message("POST DELETE COUNT: " . $variations->count()); } } else { if ($this->verbose) { DB::alteration_message("All variations have been deleted: ", "created"); } } } else { if ($this->verbose) { DB::alteration_message("This was a test only", "created"); } } } else { if ($this->verbose) { DB::alteration_message("There are no variations to delete", "created"); } } if ($this->verbose) { DB::alteration_message("Starting cleanup", "created"); } if ($live) { $sql = "\r\n\t\t\t\t\t\t\t\t\tDELETE\r\n\t\t\t\t\t\t\t\t\tFROM \"Product_VariationAttributes\"\r\n\t\t\t\t\t\t\t\t\tWHERE \"ProductID\" = " . $productID; if ($this->verbose) { DB::alteration_message("<pre>RUNNING<br />" . $sql . "</pre>"); } DB::query($sql); $sql = "\r\n\t\t\t\t\t\t\t\t\tDELETE \"ProductVariation_AttributeValues\"\r\n\t\t\t\t\t\t\t\t\tFROM \"ProductVariation_AttributeValues\"\r\n\t\t\t\t\t\t\t\t\t\tLEFT JOIN \"ProductVariation\"\r\n\t\t\t\t\t\t\t\t\t\t\tON \"ProductVariation_AttributeValues\".\"ProductVariationID\" = \"ProductVariation\".\"ID\"\r\n\t\t\t\t\t\t\t\t\tWHERE \"ProductVariation\".\"ID\" IS NULL"; if ($this->verbose) { DB::alteration_message("<pre>RUNNING<br />" . $sql . "</pre>"); } DB::query($sql); } else { $sql = "\r\n\t\t\t\t\t\t\t\t\tSELECT COUNT(Product_VariationAttributes.ID)\r\n\t\t\t\t\t\t\t\t\tFROM \"Product_VariationAttributes\"\r\n\t\t\t\t\t\t\t\t\tWHERE \"ProductID\" = " . $productID; if ($this->verbose) { DB::alteration_message("<pre>RUNNING<br />" . $sql . "</pre>"); } $result = DB::query($sql); if ($this->verbose) { DB::alteration_message("Would have deleted " . $result->value() . " rows"); } $sql = "\r\n\t\t\t\t\t\t\t\t\tSELECT COUNT (\"ProductVariation_AttributeValues\".\"ID\")\r\n\t\t\t\t\t\t\t\t\tFROM \"ProductVariation_AttributeValues\"\r\n\t\t\t\t\t\t\t\t\t\tLEFT JOIN \"ProductVariation\"\r\n\t\t\t\t\t\t\t\t\t\t\tON \"ProductVariation_AttributeValues\".\"ProductVariationID\" = \"ProductVariation\".\"ID\"\r\n\t\t\t\t\t\t\t\t\tWHERE\r\n\t\t\t\t\t\t\t\t\t\t\"ProductVariation\".\"ID\" IS NULL OR\r\n\t\t\t\t\t\t\t\t\t\t\"ProductVariation\".\"ID\" IN(" . implode(",", $productVariationArrayID) . ") "; if ($this->verbose) { DB::alteration_message("<pre>RUNNING<br />" . $sql . "</pre>"); } $result = DB::query($sql); if ($this->verbose) { DB::alteration_message("Would have deleted " . $result->value() . " rows"); } } } } } else { if ($this->verbose) { DB::alteration_message("Product does not exist. You can set the product by adding it productid=XXX as a GET variable. You can also add <i>all</i> to delete ALL product Variations.", "deleted"); } } DB::alteration_message("Completed", "created"); }
/** * Conditions for whether a product can be purchased: * - global allow purchase is enabled * - product AllowPurchase field is true * - if variations, then one of them needs to be purchasable * - if not variations, selling price must be above 0 * * Other conditions may be added by decorating with the canPurcahse function * * @param Member $member * @param int $quantity * * @throws ShopBuyableException * * @return boolean */ public function canPurchase($member = null, $quantity = 1) { $global = self::config()->global_allow_purchase; if (!$global || !$this->AllowPurchase) { return false; } $allowpurchase = false; $extension = self::has_extension("ProductVariationsExtension"); if ($extension && ProductVariation::get()->filter("ProductID", $this->ID)->first()) { foreach ($this->Variations() as $variation) { try { if ($variation->canPurchase($member, $quantity)) { $allowpurchase = true; break; } } catch (ShopBuyableException $e) { } } // if not allowed to buy after any variations then raise the last // exception again if (!$allowpurchase && isset($e)) { throw $e; return false; } } else { if ($this->sellingPrice() > 0 || self::config()->allow_zero_price) { $allowpurchase = true; } } // Standard mechanism for accepting permission changes from decorators $extended = $this->extendedCan('canPurchase', $member, $quantity); if ($allowpurchase && $extended !== null) { $allowpurchase = $extended; } return $allowpurchase; }
public function testVariationMatrix() { $size = ProductVariationType::getNewInstance($this->product); $size->setValueByLang('name', 'en', 'Size'); $size->save(); $color = ProductVariationType::getNewInstance($this->product); $color->setValueByLang('name', 'en', 'Color'); $color->save(); $sizes = $colors = array(); foreach (array('Small', 'Large') as $name) { $variation = ProductVariation::getNewInstance($size); $variation->setValueByLang('name', 'en', $name); $variation->save(); $sizes[] = $variation; } foreach (array('Red', 'Green', 'Blue') as $name) { $variation = ProductVariation::getNewInstance($size); $variation->setValueByLang('name', 'en', $name); $variation->save(); $colors[] = $variation; } // create product variations $variations = array(); foreach ($sizes as $sizeVar) { foreach ($colors as $colorVar) { $child = $this->product->createVariation(array($sizeVar, $colorVar)); $child->save(); $variations[$sizeVar->getID()][$colorVar->getID()] = $child; } } $matrix = $this->product->getVariationMatrix(); //var_dump($matrix); }
/** * Generates variations based on selected attributes. * * @param ProductAttributeType $attributetype * @param array $values */ public function generateVariationsFromAttributes(ProductAttributeType $attributetype, array $values) { //TODO: introduce transactions here, in case objects get half made etc //if product has variation attribute types if (!empty($values)) { //TODO: get values dataobject set $avalues = $attributetype->convertArrayToValues($values); $existingvariations = $this->owner->Variations(); if ($existingvariations->exists()) { //delete old variation, and create new ones - to prevent modification of exising variations foreach ($existingvariations as $oldvariation) { $oldvalues = $oldvariation->AttributeValues(); foreach ($avalues as $value) { $newvariation = $oldvariation->duplicate(); $newvariation->InternalItemID = $this->owner->InternalItemID . '-' . $newvariation->ID; $newvariation->AttributeValues()->addMany($oldvalues); $newvariation->AttributeValues()->add($value); $newvariation->write(); $existingvariations->add($newvariation); } $existingvariations->remove($oldvariation); $oldvariation->AttributeValues()->removeAll(); $oldvariation->delete(); $oldvariation->destroy(); //TODO: check that old variations actually stick around, as they will be needed for past orders etc } } else { foreach ($avalues as $value) { $variation = ProductVariation::create(); $variation->ProductID = $this->owner->ID; $variation->Price = $this->owner->BasePrice; $variation->write(); $variation->InternalItemID = $this->owner->InternalItemID . '-' . $variation->ID; $variation->AttributeValues()->add($value); $variation->write(); $existingvariations->add($variation); } } } }
<?php if ($products) { echo '<table cellpadding="0" cellspacing="0" class="shopping_cart">'; printf('<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th style="width:60px;">%s</th><th style="width:60px;">%s</th><th>%s</th></tr>', Shop::t('Image'), Shop::t('Amount'), Shop::t('Product'), Shop::t('Variation'), Shop::t('Price Single'), Shop::t('Sum'), Shop::t('Actions')); foreach ($products as $position => $product) { if (@($model = Products::model()->findByPk($product['product_id']))) { $variations = ''; if (isset($product['Variations'])) { foreach ($product['Variations'] as $specification => $variation) { $specification = ProductSpecification::model()->findByPk($specification); if ($specification->is_user_input) { $variation = $variation[0]; } else { $variation = ProductVariation::model()->findByPk($variation); } $variations .= $specification . ': ' . $variation . '<br />'; } } printf('<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td class="text-right">%s</td><td class="text-right price_' . $position . '">%s</td><td>%s</td></tr>', $model->getImage(0, true), CHtml::textField('amount_' . $position, $product['amount'], array('size' => 4, 'class' => 'amount_' . $position)), $model->title, $variations, Shop::priceFormat($model->getPrice(@$product['Variations'])), Shop::priceFormat($model->getPrice(@$product['Variations'], @$product['amount'])), CHtml::link(Shop::t('Remove'), array('//shop/shoppingCart/delete', 'id' => $position), array('confirm' => Shop::t('Are you sure?')))); Yii::app()->clientScript->registerScript('amount_' . $position, "\n\t\t\t\t\t\$('.amount_" . $position . "').keyup(function() {\n\t\t\t\t\t\t\$.ajax({\n\t\t\t\t\t\t\turl:'" . $this->createUrl('//shop/shoppingCart/updateAmount') . "',\n\t\t\t\t\t\t\tdata: \$('#amount_" . $position . "'),\n\t\t\t\t\t\t\tsuccess: function(result) {\n\t\t\t\t\t\t\t\$('.amount_" . $position . "').css('background-color', 'lightgreen');\n\t\t\t\t\t\t\t\$('.widget_amount_" . $position . "').css('background-color', 'lightgreen');\n\t\t\t\t\t\t\t\$('.widget_amount_" . $position . "').html(\$('.amount_" . $position . "').val());\n\t\t\t\t\t\t\t\$('.price_" . $position . "').html(result);\t\n\t\t\t\t\t\t\t\$('.price_total').load('" . $this->createUrl('//shop/shoppingCart/getPriceTotal') . "');\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\terror: function() {\n\t\t\t\t\t\t\t\$('#amount_" . $position . "').css('background-color', 'red');\n\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\t\t"); } } if ($shippingMethod = Shop::getShippingMethod()) { printf('<tr> <td></td> <td>1</td> <td>%s</td> <td></td> <td class="text-right">%s</td>