*/
public function exportToXlsx(ProductMappingFilterForm $filters): string
{
- $query = $this->buildFilteredQuery($filters)->orderBy(['n.name' => SORT_ASC]);
-
- /** @var Products1cNomenclature[] $products */
- $products = $query->all();
- $mappingsByGuid = $this->loadMappingsForProducts(
- array_map(static fn($p) => $p->id, $products)
- );
+ // Шаг 1: получаем отфильтрованные GUID-ы (только строки, не AR-объекты)
+ $guids = $this->buildFilteredQuery($filters)
+ ->select(['n.id'])
+ ->orderBy(['n.name' => SORT_ASC])
+ ->column();
$runtimeDir = Yii::getAlias('@runtime');
if (!is_dir($runtimeDir)) {
}
$path = $runtimeDir . '/product-mapping-export-' . date('YmdHis') . '-' . uniqid() . '.csv';
- $fh = fopen($path, 'w');
- // BOM для корректного открытия в Excel
- fwrite($fh, "\xEF\xBB\xBF");
+ $fh = fopen($path, 'wb');
+ if ($fh === false) {
+ throw new \RuntimeException('Не удалось создать файл экспорта: ' . $path);
+ }
+
+ fwrite($fh, "\xEF\xBB\xBF"); // UTF-8 BOM для Excel
fputcsv($fh, [
- 'GUID товара',
- 'Название товара 1С',
- 'Категория',
- 'Подкатегория',
- 'Вид',
- 'Поставщик',
- 'Название у поставщика',
- 'Плантация',
- 'Артикул',
- 'Штрихкод',
- 'Квант',
- 'Маркировки (коды)',
+ 'GUID товара', 'Название товара 1С', 'Категория', 'Подкатегория', 'Вид',
+ 'Поставщик', 'Название у поставщика', 'Плантация', 'Артикул', 'Штрихкод',
+ 'Квант', 'Маркировки (коды)',
], ';');
- foreach ($products as $product) {
- $mappings = $mappingsByGuid[$product->id] ?? [];
-
- if (empty($mappings)) {
- fputcsv($fh, [
- $product->id,
- $product->name,
- $product->category ?? '',
- $product->subcategory ?? '',
- $product->species ?? '',
- '', '', '', '', '', '', '',
- ], ';');
- continue;
- }
-
- foreach ($mappings as $mapping) {
- $markingCodes = array_map(static fn($m) => $m->code, $mapping->markings);
+ if (!empty($guids)) {
+ // Шаг 2: один JOIN-запрос — скаляры, не объекты, STRING_AGG для маркировок
+ $rows = (new Query())
+ ->select([
+ 'guid' => 'n.id',
+ 'product_name' => 'n.name',
+ 'category' => "COALESCE(n.category, '')",
+ 'subcategory' => "COALESCE(n.subcategory, '')",
+ 'species' => "COALESCE(n.species, '')",
+ 'supplier_name' => "COALESCE(s.name, '')",
+ 'supplier_product_name'=> "COALESCE(pm.supplier_product_name, '')",
+ 'plantation_name' => "COALESCE(pl.name, '')",
+ 'article' => "COALESCE(pm.article, '')",
+ 'barcode' => "COALESCE(pm.barcode, '')",
+ 'quant' => 'COALESCE(pm.quant, 0)',
+ 'marking_codes' => new Expression(
+ "COALESCE(STRING_AGG(mk.code, ', ' ORDER BY mk.code), '')"
+ ),
+ ])
+ ->from(['n' => 'products_1c_nomenclature'])
+ ->leftJoin(['pm' => '{{%erp24.product_mappings}}'], 'pm.product_guid = n.id')
+ ->leftJoin(['s' => '{{%erp24.suppliers}}'], 's.id = pm.supplier_id')
+ ->leftJoin(['pl' => '{{%erp24.plantations}}'], 'pl.id = pm.plantation_id')
+ ->leftJoin(['mm' => '{{%erp24.mapping_markings}}'], 'mm.mapping_id = pm.id')
+ ->leftJoin(['mk' => '{{%erp24.markings}}'], 'mk.id = mm.marking_id')
+ ->where(['n.id' => $guids])
+ ->groupBy([
+ 'n.id', 'n.name', 'n.category', 'n.subcategory', 'n.species',
+ 's.name', 'pm.id', 'pm.supplier_product_name',
+ 'pl.name', 'pm.article', 'pm.barcode', 'pm.quant',
+ ])
+ ->orderBy(['n.name' => SORT_ASC, 'pm.id' => SORT_ASC])
+ ->all();
+
+ foreach ($rows as $row) {
fputcsv($fh, [
- $product->id,
- $product->name,
- $product->category ?? '',
- $product->subcategory ?? '',
- $product->species ?? '',
- $mapping->supplier->name ?? '',
- $mapping->supplier_product_name,
- $mapping->plantation->name ?? '',
- $mapping->article ?? '',
- $mapping->barcode ?? '',
- (int)$mapping->quant,
- implode(', ', $markingCodes),
+ $row['guid'],
+ $row['product_name'],
+ $row['category'],
+ $row['subcategory'],
+ $row['species'],
+ $row['supplier_name'],
+ $row['supplier_product_name'],
+ $row['plantation_name'],
+ $row['article'],
+ $row['barcode'],
+ $row['quant'],
+ $row['marking_codes'],
], ';');
}
}