diff --git a/mirzaev/skillparts/system/models/Order.php b/mirzaev/skillparts/system/models/Order.php index 1c7e149..6949f5c 100644 --- a/mirzaev/skillparts/system/models/Order.php +++ b/mirzaev/skillparts/system/models/Order.php @@ -6,42 +6,34 @@ namespace app\models; use yii; -use app\models\Account; -use app\models\Product; -use app\models\SupplyEdgeProduct; -use app\models\traits\Xml2Array; +use app\models\traits\SearchByEdge; -use carono\exchange1c\interfaces\OfferInterface; -use carono\exchange1c\interfaces\ProductInterface; use carono\exchange1c\controllers\ApiController; +use carono\exchange1c\interfaces\DocumentInterface; -use exception; +use Exception; /** - * Поставка (выгрузка товаров от поставщиков) + * Заказ * - * Представляет собой предложения от поставщиков которые добавляются - * в универсальные лоты товаров в асспортименте магазина - * - * @see Product Продукт (туда добавляются поставки) + * @see Account Заказчик + * @see Supply Поставки для заказа */ -class Supply extends Product implements ProductInterface, OfferInterface +class Order extends Document implements DocumentInterface { - use Xml2Array; + use SearchByEdge; /** - * Количество - * - * Используется при выводе в корзине + * Поставки для записи */ - public int $amnt = 0; + public array $supplies; /** * Имя коллекции */ public static function collectionName(): string { - return 'supply'; + return 'order'; } /** @@ -52,10 +44,8 @@ class Supply extends Product implements ProductInterface, OfferInterface return array_merge( parent::attributes(), [ - 'cost', - 'onec', - 'oemn', - 'ocid' + 'ocid', + 'sync' ] ); } @@ -68,10 +58,8 @@ class Supply extends Product implements ProductInterface, OfferInterface return array_merge( parent::attributeLabels(), [ - 'cost' => 'Стоимость (cost)', - 'onec' => 'Данные 1С', - 'oemn' => 'OEM-номера', - 'ocid' => 'Идентификатор 1C (ocid)' + 'ocid' => 'Идентификатор 1C', + 'sync' => 'Статус синхронизации с 1C' ] ); } @@ -84,492 +72,443 @@ class Supply extends Product implements ProductInterface, OfferInterface return array_merge( parent::rules(), [ - // [ - // [ - // 'oemn' - // ], - // 'arrayValidator', - // 'message' => '{attribute} должен быть массивом.' - // ] + [ + 'sync', + 'boolean', + 'message' => '{attribute} должен иметь логическое значение' + ], + [ + 'sync', + 'default', + 'value' => false + ] ] ); } /** - * После сохранения + * Подключение к аккаунту */ - public function afterSave($data, $vars): void + public function connect(Account $account): ?AccountEdgeOrder { - if (AccountEdgeSupply::searchByVertex(yii::$app->user->id, $this->readId())) { - // Ребро: "АККАУНТ -> ПОСТАВКА" уже существует - - } else { - // Ребра не существует - - // Запись ребра: АККАУНТ -> ПОСТАВКА - (new AccountEdgeSupply)->write(yii::$app->user->id, $this->readId(), 'import'); - } + // Запись ребра: АККАУНТ -> ЗАКАЗ + return AccountEdgeOrder::write($account->id, $this->readId(), 'current') ?? throw new Exception('Не удалось инициализировать ребро: АККАУНТ -> ЗАКАЗ'); } /** - * Запись реквизитов из 1С - */ - public function setRequisite1c($name, $value): mixed - { - return true; - } - - /** - * Запись группы из 1С - */ - public function setGroup1c($group): mixed - { - // Чтение группы - // if ($group = SupplyGroup::readByOcid($group->id)) { - // // Запись ребра: ПОСТАВКА => ГРУППА ПОСТАВОК - // return static::writeEdgeBetweenGroup(static::collectionName() . '/' . $this->_key, $group->collectionName() . '/' . $group->_key); - // } - - return true; - } - - /** - * Поиск через связь с аккаунтом + * Запись товара * - * @param string|null $id Идентификатор пользователя - * @param string|array|null $select Запрашиваемые значения - */ - public static function searchByAccount(string|null $id = null, string|array|null $select = null, int|null $limit = 10): array - { - isset($id) ?: $id = yii::$app->user->id ?? throw new Exception('Не найден идентификатор'); - - return self::searchByEdge( - from: 'account', - to: 'supply', - subquery_where: [ - [ - 'account._id' => $id - ] - ], - where: 'supply._id == account_edge_supply[0]._to AND supply.onec["ЗначенияСвойств"] != null', - select: $select, - limit: $limit - ); - } - - /** - * Запись данных свойств по UUID 1C + * $supply = [ Supply $supply, int $amount = 1 ] * - * Ищет записанные свойства из 1C по их идентификатору и добавляет к ним - * недостающие данные. Это костыль оставшийся от реляционных баз данных + * @param Supply|array $supply Поставка + * @param Account $trgt Заказчик * - * @todo Понять что может храниться внутри "$model->onec['ЗначенияСвойств']['ЗначенияСвойства']" и переписать + * @return int Количество записанных поставок + * + * @todo Создать параметр разделителя для администрации */ - public static function createProperties1c($properties, Account|null $account = null): void + public function writeSupply(Supply|string|array $supply, Account $trgt = null): int { // Инициализация - $account ?? $account = yii::$app->user->identity; - $models = self::searchByAccount($account->readId()); - $properties = self::xml2array($properties->xml); + $trgt ?? $trgt = yii::$app->user ?? throw new Exception('Не удалось инициализировать заказчика'); - $account->on(ApiController::EVENT_AFTER_OFFER_SYNC, self::afterImport1c()); + if ($supply instanceof Supply) { + // Передана инстанция класса поставки или второй элемент массива не является числом - foreach ($models as $model) { - // Перебор записей + // Унификация входных данных + $supply = [$supply->catn => 1]; + } + + if (is_null($this->_key)) { + // Корзина не инициализирована // Инициализация - $changes = false; - $transit = $model->onec; + if (!$this->save()) { + // Инициализация заказа не удалась - foreach ($model->onec['ЗначенияСвойств'] as $attribute_name => $attribute_value) { - // Перебор аттрибутов - - foreach ($properties as $property) { - // Перебор свойств - - if (is_array($attribute_value) && is_array($property) && $attribute_value['Ид'] === $property['Ид']) { - // Совпадение идентификаторов - - // Объединение данных - $transit['ЗначенияСвойств'][$attribute_name] = array_merge($attribute_value, $property, $transit['ЗначенияСвойств'][$attribute_name]); - - // Запись индикатора наличия изменений - $changes = true; - } else { - // Объединение данных - $transit['ЗначенияСвойств'][$attribute_name] = $property; - } - } + throw new Exception('Ошибка при записи заказа в базу данных'); } - if ($changes) { - // Если указано, что записаны изменения + // Инициализация ребра: АККАУНТ -> ЗАКАЗ + if (!AccountEdgeOrder::write($trgt->readId(), $this->readId(), 'create')) { + // Инициализация не удалась - // Настройка ($transit нужен из-за особенностей __set()) - $model->onec = $transit; - - foreach ($model->onec['ЗначенияСвойств'] as $property) { - // Перебор всех свойств - - if (is_array($property)) { - // if ($property['Ид'] === $account->opts['import_sections_oem']) { - // // Если идентификатор свойства совпадает с указанным в настройках свойства хранящего OEM номера - - // Настройка - $model->catn = $property['Значение']; - // } - } - } - - // Запись - $model->save(); + throw new Exception('Ошибка при записи ребра от аккаунта до заказа в базу данных'); } } + + // Инициализация + $amount = 0; + + foreach (is_array($supply) ? $supply : [$supply => 1] as $supply_raw => $amount_raw) { + // Перебор поставок + + for ($i = 0; $i < $amount_raw; $i++) { + // Создание рёбер соразмерно запросу (добавление нескольких продуктов в корзину) + + // Запись ребра: ЗАКАЗ -> ПОСТАВКА + if (!$supply_model = Supply::searchByCatn($supply_raw) or !OrderEdgeSupply::write($this->readId(), $supply_model->readId(), 'write')) { + // Поставка не найдена или запись ребра не удалась + + continue; + } else { + // Ребро создано (товар подключен к заказу) + + // Постинкрементация счётчика добавленных товаров + $amount++; + + // Запись в журнал + $this->journal('write', ['target' => $supply_model->readId()]); + } + } + } + + if ($amount === 0) { + // Отправка уведомления + self::notification('Неудачная попытка добавить товар в корзину'); + } else if ($amount === 1) { + // Отправка уведомления + self::notification('Товар ' . $supply_model->catn . ' добавлен в корзину'); + } else { + // Отправка уведомления + self::notification('Добавлено ' . $amount . ' товаров в корзину'); + } + + return $amount; } /** - * Запись параметров из 1С - */ - public function setProperty1c($property): mixed - { - return true; - } - - /** - * Запись изображений из 1С + * Удаление поставки * - * @todo Добавить параметры в админ-панель - * Запретить доступ к изображениям + * @param Supply|string|array $supply Товары + * + * @return int Количество удалённых рёбер */ - public function addImage1c($path, $caption): bool + public function deleteSupply(Supply|string|array $supply): int { // Инициализация - $i = 0; + $amount = 0; - if (!file_exists(YII_PATH_PUBLIC . $catalog = '/img/supplies/' . $this->_key)) { - // Директория для изображений продукта не найдена + if ($supply instanceof Supply) { + // Передана инстанция класса поставки или второй элемент массива не является числом - if (!mkdir(YII_PATH_PUBLIC . $catalog, 0775, true)) { - // не удалось записать директорию - - return false; - }; + // Унификация входных данных + $supply = [$supply->catn => 1]; } - foreach ($this->imgs ?? [] as $image) { - // Перебор имеющихся изображений + foreach (is_array($supply) ? $supply : [$supply => 1] as $catn => $amount_raw) { + // Перебор товаров - if ($path === $image['sorc']) { - // Изображение уже записано на сервер + if ($supply = Supply::searchByCatn($catn)) { + foreach (OrderEdgeSupply::searchByVertex($this->readId(), $supply->readId(), limit: $amount_raw) as $edge) { + // Перебор рёбер до продукта (если товаров в заказе несколько) - return true; + // Удаление + $edge->delete(); + + // Запись в журнал + $this->journal('delete', ['target' => $supply->readId()]); + + // Постинкрементация счётчика удалённых рёбер + $amount++; + } } } + if ($amount === 0) { + // Отправка уведомления + self::notification('Неудачная попытка удалить товар из корзины'); + } else if ($amount === 1) { + // Отправка уведомления + self::notification('Товар ' . $supply->catn . ' удалён из корзины'); + } else { + // Отправка уведомления + self::notification('Удалено ' . $amount . ' товаров из корзины'); + } + + return $amount; + } + + /** + * Поиск заказа + */ + public static function search(Account $account = null, string $type = 'current', int $limit = 1, int $page = 1, string $select = null): self|array|null + { // Инициализация - $urn = basename($path); + $account or $account = yii::$app->user ?? throw new Exception('Не удалось инициализировать пользователя'); - // Запись - copy($path, $path_local = YII_PATH_PUBLIC . $catalog . '/' . $urn); + // Генерация сдвига по запрашиваемым данным (пагинация) + $offset = $limit * ($page - 1); - // Запись свойства - $this->imgs = array_merge( - $this->imgs ?? [], - [ + if (strcasecmp($type, 'all') !== 0) { + // Если не указан параметр поиска всех заказов + + $where_type = [ + 'account_edge_order.type' => $type + ]; + } else { + $where_type = []; + } + + $return = self::searchByEdge( + from: 'account', + to: 'order', + subquery_where: [ [ - 'dscr' => $caption, - 'path' => $path_local, - 'sorc' => $path - ] - ] + 'account._id' => $account->id + ], + $where_type + ], + foreach: ['edge' => 'account_edge_order'], + where: 'edge._to == order._id', + limit: $limit, + offset: $offset, + sort: ['DESC'], + select: $select, + direction: 'INBOUND' ); - // Отправка в базу данных - return $this->update(); + return $limit === 1 ? $return[0] ?? null : $return; } /** - * Запись ребра (предложения от поставок к продуктам) из 1С + * Поиск содержимого заказа * - * @todo Разобраться зачем нужно возвращать SupplyEdgeProduct - * Вернуть создание карточек, но только по условиям (загрузка от админа, например) + * @todo В будущем возможно заказ не только поставок реализовать */ - public function getOffer1c($offer): SupplyEdgeProduct + public function content(int $limit = 1, int $page = 1): Supply|array|null { - if (empty($this->catn)) { - // Не передан каталожный номер + // Генерация сдвига по запрашиваемым данным (пагинация) + $offset = $limit * ($page - 1); - // Разработчику библеотеки надо дать по жопе - return new SupplyEdgeProduct; - } + // Поиск рёбер: ЗАКАЗ -> ПОСТАВКА + $supplies = Supply::searchByEdge( + from: 'order', + to: 'supply', + edge: 'order_edge_supply', + subquery_where: [ + [ + 'order._id' => $this->readId() + ] + ], + foreach: ['edge' => 'order_edge_supply'], + where: 'edge._to == supply._id', + limit: $limit, + offset: $offset, + direction: 'INBOUND' + ); - if ( - !yii::$app->user->isGuest - && yii::$app->user->identity->agnt - && (yii::$app->user->identity->type === 'administrator' - || yii::$app->user->identity->type === 'moderator') - ) { - // Пользователь аутентифицирован и авторизован + // Инициализация реестра дубликатов + $registry = []; - // Инициализация п̸̨͇͑͋͠р̷̬̂́̀̊о̸̜̯̹̅͒͘͝д̴̨̨̨̟̈́̆у̴̨̭̮̠́͋̈́к̴̭͊̋̎т̵̛̣͈̔̐͆а̵̨͖͑ - $product = self::initEmpty($this->catn); + // Подсчёт и перестройка массива для очистки от дубликатов + foreach ($supplies as $key => &$supply) { + // Перебор поставок - if (!is_array($product)) { - // Создался только один товар и вернулся в виде модели + if (in_array($supply->catn, $registry)) { + // Если данная поставка найдена в реестре - $product = [$product]; - } - - if (is_array($this->oemn)) { - // Значение OEM было инициализировано - - foreach ($this->oemn as $oem) { - // Перебор артикулов из массива ОЕМ-номеров - - // Инициализация и запись - $product[] = self::initEmpty($oem); - } - } - - foreach ($product as $product) { - // Перебор всех инициализированных продуктов - - if ($this->catn !== $product->catn) { - // Каталожные номера не соответствуют друг другу - - continue; - } - - // Код ниже скорее всего устарел - - if (SupplyEdgeProduct::searchByVertex($this->readId(), $product->readId())) { - // Ребро уже существует - - continue; - } - - // Запись ребра: ПОСТАВКА -> ПРОДУКТ - $return = (new SupplyEdgeProduct)->write( - $this->readId(), - $product->readId(), - 'connect', - [ - 'onec' => self::xml2array($offer->xml) - ] - ); - } - } - - // Возвращает последнее сохранённое ребро - // Надо будет с этим разобраться - return $return ?? new SupplyEdgeProduct(); - } - - /** - * Запись продукта из 1С (поставка) - * - * @see Supply - * - * @todo Понять что может храниться внутри "$model->onec['ЗначенияСвойств']['ЗначенияСвойства']" и переписать - * Разобраться и создать возможность загрузки от лица другого аккаунта - */ - public static function createModel1c($product): ?self - { - // Инициализация - $model = self::searchByOcid($id = (string) $product->Ид) ?? new self; - $account ?? $account = yii::$app->user->identity; - - // Настройка - $model->ocid = $id ?? null; - $model->catn = (string) $product->Артикул; - $model->dscr = (string) $product->Описание; - $model->onec = self::xml2array($product->xml); - - if (isset($model->onec['ЗначенияСвойств'])) { - // Свойства инициализированы - - foreach ($model->onec['ЗначенияСвойств'] as $property) { - // Перебор всех свойств - - if (is_array($property)) { - if (!empty($account->opts['import_sections_oem']) && $property['Ид'] === $account->opts['import_sections_oem']) { - // Если идентификатор свойства совпадает с указанным в настройках свойства хранящего OEM номера - - // Настройка - $model->oemn = array_merge(self::searchOemn($property['Значение']), self::searchOemn((string) $product->Артикул)); - } - } - } - } - - // Запись - if ($model->save()) { - // Поставка успешно сохранена - - return $model; - } - - return null; - } - - /** - * @param mixed|null $context - * @return array - */ - public function getExportFields1c($context = null) { - return $this->onec; - } - - /** - * Инициализация продукта - * - * @param string $catn Артикул, каталожный номер - */ - public static function initEmpty(string $catn): Product|array - { - $oemn = self::searchOemn($catn); - - if (count($oemn) === 1) { - // Передан только один артикул - - if ($model = Product::searchByCatn($catn)) { - // Продукт уже существует - - return $model; - } - - // Запись пустого продукта - return Product::writeEmpty($catn); - } - - // Инициализация - $models = []; - - foreach ($oemn as $catn) { - // Перебор всех найденных артикулов - - if ($model = Product::searchByCatn($catn)) { - // Продукт уже существует + // Удаление + unset($supplies[$key]); + // Пропуск итерации continue; } - // Запись - if ($model = Product::writeEmpty($catn)) { - // Записано + // Инициализация + $amount = 0; - // Запись в массив сохранённых моделей - $models[] = $model; + // Повторный перебор для поиска дубликатов + foreach ($supplies as &$supply4check) { + if ($supply == $supply4check) { + // Найден дубликат + + // Постинкрементация счётчика + $amount++; + + // Запись в реестр + $registry[] = $supply4check->catn; + } + } + + // Запись количества для заказа + $supply->amnt = $amount; + } + + // Поиск стоимости для каждой поставки + foreach ($supplies as $key => &$supply) { + // Перебор поставок + + // Чтение стоимости + $cost = $supply->readCost(); + + if ($cost < 1) { + // Если стоимость равна нулю (явная ошибка) + + // Удаление из базы данных + $this->deleteSupply($supply->readId()); + + // Удаление из списка + unset($supplies[$key]); + + // Пропуск итерации + continue; + } + + // Запись цены + $supply->cost = $cost['ЦенаЗаЕдиницу'] . ' ' . $cost['Валюта']; + } + + return $supplies; + } + + /** + * @return DocumentInterface[] + */ + public static function findDocuments1c(): ?array + { + // yii::$app->on(ApiController::EVENT_AFTER_EXPORT_ORDERS, self::afterExport1c()); + + $orders = self::searchByEdge( + from: 'account', + to: 'order', + edge: 'account_edge_order', + direction: 'INBOUND', + subquery_where: 'account_edge_order.type == "processed"', + where: ['sync' => false] + ); + + foreach ($orders as &$order) { + // Перебор заказов + + // Запись о том, что синхронизация проведена + $order->sync = true; + + $order->update(); + } + + return $orders; + } + + /** + * @return OfferInterface[] + */ + public function getOffers1c(): mixed + { + // Инициализация + $supplies = []; + + foreach ($this->jrnl as $key => $jrnl) { + // Перебор журнала + + // if (isset($supplies[$key]) && $supplies[$key]['id'] !== $jrnl['target']) { + // // Запись уже существует и идентификаторы не совпадают + + // $key .= '_du' + + // // Реинициализация + // $supplies[$key]['id'] = $jrnl['target']; + // } else { + // // Инициализация + // } + + + if (($jrnl['action'] ?? null) === 'write') { + // Найдено событие записи товара к заказу + + $supplies[$key]['id'] = $jrnl['target']; + + $supplies[$key]['amount'] ?? $supplies[$key]['amount'] = 0; + + ++$supplies[$key]['amount']; + } else if (($jrnl['action'] ?? null) === 'delete') { + // Найдено событие удаления товара из заказа + + $supplies[$key]['id'] = $jrnl['target']; + + $supplies[$key]['amount'] ?? $supplies[$key]['amount'] = 0; + + --$supplies[$key]['amount']; } } - return $models; + file_put_contents('supplies.txt', print_r($supplies, true)); + + if (count($supplies) > 0) { + // Поставки были записаны + + // Инициализация + $supplies_buffer = []; + + foreach ($supplies as $id => $supply) { + // Перебор поставок + + if ($supply['amount'] < 1) { + continue; + } + + if ($response = Supply::searchById($supply['id'])) { + // Поставка найдена в базе данных + + $supplies_buffer[] = $response; + } + } + + return $supplies_buffer; + } + file_put_contents('AAAAAAAAAAAAAAAAAAA.txt', print_r(1, true)); + + return []; } /** - * Поиск OEM номеров - * - * @param string $oemn Необработанная строка с OEM-номерами - * @param string $delimiters Разделители - * - * @todo НЕ ЗАБЫТЬ СДЕЛАТЬ НАСТРОЙКУ РАЗДЕЛИТЕЛЕЙ - * - * @return array OEM-номера + * Неизвестно для чего */ - public static function searchOemn(string $oemn, string $delimiters = '\s\+\/,'): array + public function getRequisites1c(): void { - // Инициализация - $catn = []; - - // Конвертация - preg_match_all("/[^$delimiters]+/", $oemn, $catn); - - return $catn[0]; + // return true; } /** - * Запись цены из 1С - */ - public function setPrice1c($price) - { - } - - /** - * @param $types - * @return void - */ - public static function createPriceTypes1c($types) { - } - - /** - * offers.xml > ПакетПредложений > Предложения > Предложение > ХарактеристикиТовара > ХарактеристикаТовара + * Получить контрагента (пользователя от лица которого происходит операция) * - * Характеристики товара - * $name - Наименование - * $value - Значение - * - * @param \Zenwalker\CommerceML\Model\Simple $specification - * @return void + * @return PartnerInterface */ - public function setSpecification1c($specification) { - - } - - /** - * Запись данных на случай ошибки при экспорте из 1С - */ - public function setRaw1cData($cml, $object): bool + public function getPartner1c(): Account { - return true; + return yii::$app->user->identity ?? throw new Exception('Не удалось идентифицировать пользователя'); } - /** - * Поиск по идентификатору из 1С - * - * @param string $ocid Идентификатор из 1С - * - * @return Supply|null - */ - public static function searchByOcid(string $ocid): ?Supply - { - return static::findOne([static::getIdFieldName1c() => $ocid]); - } - - /** - * Чтение группы из 1С - */ - public function getGroup1c(): ?SupplyGroup - { - return new SupplyGroup(); - } - - /** - * Чтение названия поля в котором хранится идентификатор из 1С - */ - public static function getIdFieldName1c(): string - { - return 'ocid'; - } - - /** - * Поиск по OEM-номерам - * - * @todo Реализовать с помощью LIKE - */ - public static function searchByOemn(): array + public function getExportFields1c($context = null) { return []; } /** - * Прочитать стоимость + * Возвращаем имя поля в базе данных, в котором хранится ID из 1с + * + * @return string */ - public function readCost(Product $product = null): array + public static function getIdFieldName1c() { - if (isset($product)) { - return SupplyEdgeProduct::searchByVertex($this->readId(), $product->readId(), type: 'connect', limit: 1)['onec']['Цены']['Цена']; - } + return 'ocid'; + } - return SupplyEdgeProduct::search($this->readId(), type: 'connect', limit: 1)['onec']['Цены']['Цена']; + public function setRaw1cData($cml, $object): void + { + } + + protected static function afterExport1c(): void + { + file_put_contents('afterExport1c.txt', print_r(1, true)); + } + + /** + * Отправка уведомления + */ + public static function notification(string $text, string|null $type = Notification::TYPE_NOTICE): Notification|array|null + { + // Отправка + return Notification::_write($text, type: $type); } } diff --git a/mirzaev/skillparts/system/models/Supply.php b/mirzaev/skillparts/system/models/Supply.php index 26a9e5b..1c7e149 100644 --- a/mirzaev/skillparts/system/models/Supply.php +++ b/mirzaev/skillparts/system/models/Supply.php @@ -412,37 +412,12 @@ class Supply extends Product implements ProductInterface, OfferInterface return null; } - /** - * @param $types - * @return void - */ - public static function createPriceTypes1c($types) { - return 100; - } - - /** - * offers.xml > ПакетПредложений > Предложения > Предложение > ХарактеристикиТовара > ХарактеристикаТовара - * - * Характеристики товара - * $name - Наименование - * $value - Значение - * - * @param \Zenwalker\CommerceML\Model\Simple $specification - * @return void - */ - public function setSpecification1c($specification) { - - } - /** * @param mixed|null $context * @return array */ public function getExportFields1c($context = null) { - return [ - 'Ид' => 'ocid', - 'Наименование' => 'catn' - ]; + return $this->onec; } /** @@ -515,9 +490,29 @@ class Supply extends Product implements ProductInterface, OfferInterface /** * Запись цены из 1С */ - public function setPrice1c($price): mixed + public function setPrice1c($price) { - return true; + } + + /** + * @param $types + * @return void + */ + public static function createPriceTypes1c($types) { + } + + /** + * offers.xml > ПакетПредложений > Предложения > Предложение > ХарактеристикиТовара > ХарактеристикаТовара + * + * Характеристики товара + * $name - Наименование + * $value - Значение + * + * @param \Zenwalker\CommerceML\Model\Simple $specification + * @return void + */ + public function setSpecification1c($specification) { + } /** @@ -545,7 +540,7 @@ class Supply extends Product implements ProductInterface, OfferInterface */ public function getGroup1c(): ?SupplyGroup { - return $this->group; + return new SupplyGroup(); } /**