carono/yii2-1c-exchange

用于从1C交换商品和文档的Yii2模块

安装量: 18,065

依赖项: 0

建议者: 0

安全: 0

星级: 77

关注者: 11

分支: 24

开放问题: 7

类型:yii2-extension

0.3.1 2020-09-08 12:58 UTC

This package is auto-updated.

Last update: 2024-09-12 23:01:39 UTC


README

Scrutinizer Code Quality Latest Stable Version Total Downloads License

简介

这是什么模块,它应该执行哪些任务?

安装此模块应简化1C与您网站的集成。

模块包含一组必须实现的接口,以实现与1C交换商品和文档。假设您有1C:Предприятие 8, Управление торговлей", 版本11.3, 11.3.2(磁力链接),平台8.3.9.2033(及更高版本)。如果您的配置版本低于此,则模块可能仍然可以正常工作,因为1C与网站之间的交换在很大程度上不会随着版本的更新而变化。

连接模块到您的项目后,您可以通过链接获取当前文档 /exchange/article/index

模块连接

1. 通过Composer连接包

composer require carono/yii2-1c-exchange

2. 在应用程序配置中连接模块

'modules' => [
    'exchange' => [
        'class' => \carono\exchange1c\ExchangeModule::class
    ]
]

3. 如果使用Apache作为Web服务器,请勿忘记在web目录中创建和设置 .htaccess

交换模块属性

1С设置

1. 安装1C:Предприятие 8 Управление торговлей, 版本11.3, 11.3.2(磁力链接),平台8.3.9.2033(及更高版本)

设置将在演示版本上执行。

2. 通过“НСИ和行政”或通过搜索进入数据同步设置

3. 进入与网站交换的节点


4. 创建新节点并填写数据

  • 名称
  • 商品导出
  • 网站地址,指定您的 网站/1c_exchange.php
  • 用户名和密码,我们将使用该用户名导出商品(授权设置


授权设置

模块中的授权通过 \yii\filters\auth\HttpBasicAuth 实现

'modules' => [
    'exchange' => [
        'class' => \carono\exchange1c\ExchangeModule::class,
        'auth' => function ($username, $password) {
            if ($user = \app\models\User::findByUsername($username)) {
                if ($user->validatePassword($password)) {
                    return $user;
                }
            }
            return false;
        }
     ]
],


groupClass 产品组

模块设置,指定工作组模型类

[
    'exchange' => [
        'class' => \carono\exchange1c\ExchangeModule::class,
        'groupClass' => \app\models\Group::class,
    ]
]

迁移,创建用于存储产品的组,应该是具有无限嵌套的树形结构,建议使用 nested sets,但为了示例,我们使用更简单的例子

$this->createTable('{{%group}}', [
    'id' => $this->primaryKey(),
    'name' => $this->string()->comment('Наименование группы'),
    'parent_id' => $this->integer()->comment('Родительская группа'),
    'accounting_id' => $this->string()->comment('Код в 1С')->unique(),
]);

需要实现的接口列表 在这里

createTree1c

public static function createTree1c($groups)

createTree1c 函数中,我们需要实现创建整个产品树(父级->子级)。该方法仅在导入开始之前调用一次,因此在这个函数中需要完全创建所有组。

<?php
/**
 * This class is generated using the package carono/codegen
 */
namespace app\models;
use carono\exchange1c\interfaces\GroupInterface;
/**
 * This is the model class for table "group".
 */
class Group extends base\Group implements GroupInterface
{
    /**
     * Возвращаем имя поля в базе данных, в котором хранится ID из 1с
     *
     * @return string
     */
    public static function getIdFieldName1c()
    {
        return 'accounting_id';
    }
    /**
     * Создание дерева групп
     * в параметр передаётся массив всех групп (import.xml > Классификатор > Группы)
     * $groups[0]->parent - родительская группа
     * $groups[0]->children - дочерние группы
     *
     * @param \Zenwalker\CommerceML\Model\Group[] $groups
     * @return void
     */
    public static function createTree1c($groups)
    {
        foreach ($groups as $group) {
            self::createByML($group);
            if ($children = $group->getChildren()) {
                self::createTree1c($children);
            }
        }
    }
    /**
     * Создаём группу по модели группы CommerceML
     * проверяем все дерево родителей группы, если родителя нет в базе - создаём
     *
     * @param \Zenwalker\CommerceML\Model\Group $group
     * @return Group|array|null
     */
    public static function createByML(\Zenwalker\CommerceML\Model\Group $group)
    {
        /**
         * @var \Zenwalker\CommerceML\Model\Group $parent
         */
        if (!$model = Group::findOne(['accounting_id' => $group->id])) {
            $model = new self;
            $model->accounting_id = $group->id;
        }
        $model->name = $group->name;
        if ($parent = $group->getParent()) {
            $parentModel = self::createByML($parent);
            $model->parent_id = $parentModel->id;
            unset($parentModel);
        } else {
            $model->parent_id = null;
        }
        $model->save();
        return $model;
    }
}

您可以通过 这里 测试您的实现

productClass 产品模型

产品 - 产品模型是商品本身,图片,属性和规格,但不包括库存或价格。

对于不太熟悉1С中数据存储概念的开发者,需要额外的解释。在1С中存在产品和提议。产品是指商品本身,提议是指可以销售的东西,即提议参与销售。

示例

Labutene鞋子型号X是产品,它有自己的图片、各种属性(制造商、颜色、材料等),这些都是该产品的特性。

Labutene鞋子型号X,尺码32,售价20000元是提议,一个产品可能有多个提议,具有不同的属性,如尺寸和不同的价格,每个提议可能有不同的库存。

设置

在模块设置中添加您的产品模型 'productClass' => \app\models\Product::class

[
    'exchange' => [
        'class' => \carono\exchange1c\ExchangeModule::class,
        'groupClass' => \app\models\Group::class,
        'productClass' => \app\models\Product::class,
    ]
]

接口

在您的模型中实现接口 carono\exchange1c\interfaces\ProductInterface

setRequisite1c

public function setRequisite1c($name, $value)

设置产品的属性。属性列表位于 import.xml > 目录 > 商品 > 商品 > 属性值 > 属性值

为了存储属性,需要一个属性表,以及一个产品+属性+值汇总表

public function setRequisite1c($name, $value)
{
    if (!$requisite = Requisite::findOne(['name' => $name])) {
        $requisite = new Requisite();
        $requisite->name = $name;
        $requisite->save();
    }
    $this->addPivot($requisite, PvProductRequisite::class, ['value' => $value]);
}

setGroup1c

public function setGroup1c($group)

设置产品所在组。所有组都应该已经保存在数据库中,因为之前调用了方法 \carono\exchange1c\interfaces\GroupInterface::createTree1c,所有组树已经由您创建,因此不需要检查组的存在。

    public function setGroup1c($group)
    {
        $id = Group::find()->select(['id'])->andWhere(['accounting_id' => $group->id])->scalar();
        $this->updateAttributes(['group_id' => $id]);
    }

createProperties1c

public static function createProperties1c($properties)

此函数在导入时调用一次,在此函数中需要创建所有属性及其值。

    /**
     * @param PropertyCollection $properties
     * @return mixed
     */
    public static function createProperties1c($properties)
    {
        /**
         * @var \Zenwalker\CommerceML\Model\Property $property
         */
        foreach ($properties as $property) {
            $propertyModel = Property::createByMl($property);
            foreach ($property->getAvailableValues() as $value) {
                if (!$propertyValue = PropertyValue::findOne(['accounting_id' => $value->id])) {
                    $propertyValue = new PropertyValue();
                    $propertyValue->name = (string)$value->Значение;
                    $propertyValue->property_id = $propertyModel->id;
                    $propertyValue->accounting_id = (string)$value->ИдЗначения;
                    $propertyValue->save();
                    unset($propertyValue);
                }
            }
        }
    }

setProperty1c

public function setProperty1c($property)

产品属性及其值是单独的实体,因此它们需要分别存储在单独的表中,而值和产品存储在汇总表中。

所有属性已经填写,因为之前执行了 createProperties1c($properties),因此可以按id搜索属性和值。

属性值可以是单独的实体,也可以是简单的值,因此如果xml中存在 ИдЗначения 字段,则需要在值表中查找,否则应该是简单的字符串或数字。

* 在此函数中使用carono/yii2-migrate包中的特性

    
    /**
     * $property - Свойство товара (import.xml > Классификатор > Свойства > Свойство)
     * $property->value - Разыменованное значение (string) (import.xml > Классификатор > Свойства > Свойство > Значение)
     * $property->getValueModel() - Данные по значению, Ид значения, и т.д (import.xml > Классификатор > Свойства > Свойство > ВариантыЗначений > Справочник)
     *
     * @param MlProperty $property
     * @return void
     */
    public function setProperty1c($property)
    {
        $propertyModel = Property::findOne(['accounting_id' => $property->id]);
        $propertyValue = $property->getValueModel();
        if ($propertyAccountingId = (string)$propertyValue->ИдЗначения) {
            $value = PropertyValue::findOne(['accounting_id' => $propertyAccountingId]);
            $attributes = ['property_value_id' => $value->id];
        } else {
            $attributes = ['value' => $propertyValue->value];
        }
        $this->addPivot($propertyModel, PvProductProperty::class, $attributes);
    }


addImage1c

public function addImage1c($path, $caption)

在此函数中,我们获取图片的绝对路径和图像名称(用于alt属性)

* 在此函数中使用carono/yii2-migrate包中的特性和carono/yii2-file-upload包中的文件管理

    /**
     * @param string $path
     * @param string $caption
     * @return mixed
     */
    public function addImage1c($path, $caption)
    {
        if (!$this->getImages()->andWhere(['md5' => md5_file($path)])->exists()) {
            $this->addPivot(FileUpload::startUpload($path)->process(), PvProductImage::class, ['caption' => $caption]);
        }
    }

getGroup1c

public function getGroup1c()

获取当前产品所在的组,该组应继承接口 \carono\exchange1c\interfaces\GroupInterface

    /**
     * @return GroupInterface
     */
    public function getGroup1c()
    {
        return $this->group;
    }

getOffer1c

public function getOffer1c($offer)

在此函数中发送XML数据提议,需要创建或找到您的提议模型(接口 \carono\exchange1c\interfaces\OfferInterface)并返回结果。

    /**
     * @param \Zenwalker\CommerceML\Model\Offer $offer
     * @return OfferInterface
     */
    public function getOffer1c($offer)
    {
        $offerModel = Offer::createByMl($offer);
        $offerModel->product_id = $this->id;
        if ($offerModel->getDirtyAttributes()) {
            $offerModel->save();
        }
        return $offerModel;
    }

提议解析示例

    
class Offer extends BaseOffer implements OfferInterface {   
    /**
     * @param MlOffer $offer
     * @return Offer
     */
    public static function createByMl($offer)
    {
        if (!$offerModel = self::findOne(['accounting_id' => $offer->id])) {
            $offerModel = new self;
            $offerModel->name = (string)$offer->name;
            $offerModel->accounting_id = (string)$offer->id;
        }
        $offerModel->remnant = (string)$offer->Количество;
        return $offerModel;
    }
}

createModel1c

public static function createModel1c($product)

在此函数中,我们需要找到或创建新产品并返回您的模型。

    /**
     * @param \Zenwalker\CommerceML\Model\Product $product
     * @return self
     */
    public static function createModel1c($product)
    {
        if (!$model = Product::findOne(['accounting_id' => $product->id])) {
            $model = new Product();
            $model->accounting_id = $product->id;
        }
        $model->name = $product->name;
        $model->description = (string)$product->Описание;
        $model->article = (string)$product->Артикул;
        $model->save();
        return $model;
    }

offerClass 报价模型

提议是参与销售的货物模型,它有库存和价格集。

设置

在模块设置中添加您的提议模型 'offerClass' => \app\models\Offer::class

[
    'exchange' => [
        'class' => \carono\exchange1c\ExchangeModule::class,
        'groupClass' => \app\models\Group::class,
        'productClass' => \app\models\Product::class,
        'offerClass' => \app\models\Offer::class,
    ]
]

接口

在您的模型中实现接口 carono\exchange1c\interfaces\OfferInterface

getGroup1c

public function getGroup1c()

在此,我们需要获取提议所在的组。通过产品关系获取它。

* 可能未来会被getProduct1c()替代

    /**
     * @return GroupInterface
     */
    public function getGroup1c()
    {
        return $this->product->group;
    }

createPriceTypes1c

public static function createPriceTypes1c($types)

在此方法中,需要创建所有价格类型。价格类型包含名称(零售、批发等)以及货币名称。

    /**
     * @param $types
     * @return void
     */
    public static function createPriceTypes1c($types)
    {
        foreach ($types as $type) {
            PriceType::createByMl($type);
        }
    }

价格类型创建示例

class PriceType extends BasePriceType
{
    /**
     * @param Simple $type
     * @return PriceType
     */
    public static function createByMl($type)
    {
        if (!$priceType = self::findOne(['accounting_id' => $type->id])) {
            $priceType = new self;
            $priceType->accounting_id = $type->id;
        }
        $priceType->name = $type->name;
        $priceType->currency = (string)$type->Валюта;
        if ($priceType->getDirtyAttributes()) {
            $priceType->save();
        }
        return $priceType;
    }
}

setPrice1c

public function setPrice1c($price)

价格是单独的实体,因此应存储在单独的表中,并通过汇总表与提议关联。


    /**
     * offers.xml > ПакетПредложений > Предложения > Предложение > Цены
     *
     * Цена товара,
     * К $price можно обратиться как к массиву, чтобы получить список цен (Цены > Цена)
     * $price->type - тип цены (offers.xml > ПакетПредложений > ТипыЦен > ТипЦены)
     *
     * @param \Zenwalker\CommerceML\Model\Price $price
     * @return void
     */
    public function setPrice1c($price)
    {
        $priceType = PriceType::findOne(['accounting_id' => $price->getType()->id]);
        $priceModel = Price::createByMl($price, $this, $priceType);
        $this->addPivot($priceModel, PvOfferPrice::class);
    }

创建价格示例

class Price extends BasePrice
{
    /**
     * @param MlPrice $price
     * @param Offer $offer
     * @param PriceType $type
     * @return Price
     */
    public static function createByMl($price, $offer, $type)
    {
        if (!$priceModel = $offer->getPrices()->andWhere(['type_id' => $type->id])->one()) {
            $priceModel = new self();
        }
        $priceModel->value = $price->cost;
        $priceModel->performance = $price->performance;
        $priceModel->currency = $price->currency;
        $priceModel->rate = $price->rate;
        $priceModel->type_id = $type->id;
        $priceModel->save();
        return $priceModel;
    }
}

setSpecification1c

public function setSpecification1c($specification)

提供特征的属性是独立实体,并且应通过汇总表进行连接。

    /**
     * offers.xml > ПакетПредложений > Предложения > Предложение > ХарактеристикиТовара > ХарактеристикаТовара
     *
     * Характеристики товара
     * $name - Наименование
     * $value - Значение
     *
     * @param \Zenwalker\CommerceML\Model\Simple $specification
     * @return void
     */
    public function setSpecification1c($specification)
    {
        $specificationModel = Specification::createByMl($specification);
        $this->addPivot($specificationModel, PvOfferSpecification::class, ['value' => (string)$specification->Значение]);
    }

特征解析示例

class Specification extends BaseSpecification
{
    public static function createByMl($specification)
    {
        if (!$specificationModel = self::findOne(['accounting_id' => $specification->id])) {
            $specificationModel = new self;
            $specificationModel->name = $specification->name;
            $specificationModel->accounting_id = $specification->id;
            $specificationModel->save();
        }
        return $specificationModel;
    }
}

partnerClass 用户模型

目前,此接口仅用于文档交换。唯一需要实现的是公共方法 public function getExportFields1c,它描述了交换时序列化的字段。需要返回一个数组,其中键是XML中的标签,值是您的数据。所有支持的标准数据都可以在规范中找到,更详细的信息请查看xsd文件,因为官方pdf文件中存在误差。关于此方法的更多信息可以在这里查看。

设置

在模块设置中添加您的提案模型 'partnerClass' => \app\models\Partner::class

[
    'exchange' => [
        'class' => \carono\exchange1c\ExchangeModule::class,
        'groupClass' => \app\models\Group::class,
        'productClass' => \app\models\Product::class,
        'offerClass' => \app\models\Offer::class,
        'partnerClass' => \app\models\Partner::class, 
    ]
]

接口

在您的模型中实现接口 carono\exchange1c\interfaces\PartnerInterface

    public function getExportFields1c($context = null)
    {
        return [
            'Ид' => 'id',
            'Наименование' => 'username',
            'ПолноеНаименование' => 'full_name',
            'Фамилия' => 'surname',
            'Имя' => 'name',
        ];
    }

documentClass 文档模型

1C中的文档,也就是网站上的订单。文档应通过汇总表与提案相关联。建议在汇总表和订单中均标明金额,以避免动态计算,因为提案的价格可能会改变,客户最终收到的账单可能是另一个金额。

设置

在模块设置中添加您的提案模型 'documentClass' => \app\models\Document::class

[
    'exchange' => [
        'class' => \carono\exchange1c\ExchangeModule::class,
        'groupClass' => \app\models\Group::class,
        'productClass' => \app\models\Product::class,
        'offerClass' => \app\models\Offer::class,
        'partnerClass' => \app\models\Partner::class, 
        'documentClass' => \app\models\Document::class, 
    ]
]

接口

在您的模型中实现接口 carono\exchange1c\interfaces\DocumentInterface



findDocuments1c

public static function findDocuments1c()

获取所有准备好的文档(订单)。在此函数中,需要返回所有准备导入1C的文档。

请注意,如果在此函数中存在,1C将替换现有文档,因此在导入完成后,需要设置标志或更改状态,以避免在重复导入这些文档时发生。这意味着如果您已在1C中创建文档,开始使用它们或更改状态或填充数据,则在下一次导入时,它们将被重写,您将不得不从头开始。有关如何更新已导出的数据,请参阅事件部分。

    /**    
     * @return DocumentInterface[]
     */
    public static function findDocuments1c()
    {
        return self::find()->andWhere(['status_id' => 2])->all();
    }

getOffers1c

public function getOffers1c()

获取已添加到此文档(订单)的所有提案

    /**
     * @return OfferInterface[]
     */
    public function getOffers1c()
    {
        return $this->offers;
    }

getRequisites1c

public function getRequisites1c()

我还不确定这个函数在哪里使用,目前无需填写。

getPartner1c

public function getPartner1c()

需要返回下订单的用户,该类必须实现 \carono\exchange1c\interfaces\PartnerInterface

    /**
     * Получаем контрагента у документа
     *
     * @return PartnerInterface
     */
    public function getPartner1c()
    {
        return $this->user;
    }

warehouseClass 仓库模型

目前未使用

getExportFields1c

public function getExportFields1c($context = null)

在1C中创建的对象具有接口 \carono\exchange1c\interfaces\ExportFieldsInterface 以及此方法。在此方法中,我们应该返回一个数组,该数组被序列化为1C的XML。数组的键是XML中的标签名称。

值可以是不同的类型,类似于rest api中的 fields 函数。

string - 传递属性名称,如果不存在该属性,则返回此字符串

Closure - 传递函数 function($model)

array - 使用数组可以自定义XML,或者当需要创建多个元素时。在此数组中,有一些保留的键:@content - 标签体,@name - 标签名,@attributes - 属性数组。

所有值都会递归处理,因此可以构建复杂的结构。

输入参数 $context - 是序列化对象的上下文,例如对于提案,上下文将是订单。

文档中合同方序列化示例。

    public function getExportFields1c($context = null)
    {
        return [
            'Ид' => 'id',
            'Наименование' => 'login',
            'ПолноеНаименование' => 'full_name',
            'Фамилия' => 'surname',
            'Имя' => 'name',
            'Контакты' => [
                [
                    '@name' => 'Контакт',
                    'Тип' => 'Почта',
                    'Значение' => $this->email,
                ],
                [
                    '@name' => 'Контакт',
                    'Тип' => 'ТелефонРабочий',
                    'Значение' => $this->phone,
                ],
            ],
        ];
    }

结果

<Контрагенты>
    <Контрагент>
        <Ид>13</Ид>
        <Наименование>info@carono.ru</Наименование>
        <ПолноеНаименование>Иванов Иван Иванович</ПолноеНаименование>
        <Контакт>
            <Тип>Почта</КонтактВид>
            <Значение>info@carono.ru</Значение>
        </Контакт>
        <Контакт>
            <Тип>ТелефонРабочий</КонтактВид>
            <Значение>+8(908)123-45-67</Значение>
        </Контакт>
    </Контрагент>
</Контрагенты>

getIdFieldName1c

public static function getIdFieldName1c()

1C中的所有实体都有一个唯一的标识符 Ид,需要返回存储此值的字段名称。

    /**
     * Возвращаем имя поля в базе данных, в котором хранится ID из 1с
     *
     * @return string
     */
    public static function getIdFieldName1c()
    {
        return 'accounting_id';
    }

setRaw1cData

public function setRaw1cData($cml, $object)

如果由于某些原因,import.xml或offers.xml文件被修改
某些数据未进入解析器,在调用此方法之前会调用此方法,
$object и $cml 可以获取所有手动解析的数据。

遗憾的是,目前并非所有实体都能通过此方法。

交换协议描述

来源:[链接](http://v8.1c.ru/edi/edi_stnd/131/)

本开放协议由“1C”公司和“1C-Битрикс”公司共同开发。

该协议用于“1C:Предприятие”系统与网站管理系统之间交换商业数据的默认程序。

功能上,交换分为两个部分

第一部分确保将商品目录和数据发布到网站上。第二部分需要将网站信息传递到“1C:Предприятие”系统,并进行订单状态和参数的同步。

在两种情况下,交换的发起者都是“1C:Предприятие”系统。电子文件的交换遵循《CommerceML 2》标准中描述的规则和格式。

在初始化交互时,建立HTTP连接。“1C:Предприятие”系统请求网站所需的参数,例如最大包体积、支持压缩等。基于这些数据,“1C:Предприятие”系统形成XML消息并将其发送到网站。

导出到网站

发布到网站的数据以一个包的形式导出。

A. 会话开始

数据导出从“1C:Предприятие”系统发送以下类型的http请求开始
http://<网站>/<路径> /1c_exchange.php?type=catalog&mode=checkauth.

作为回应,网站管理系统向“1C:Предприятие”系统发送三行(使用换行符"\n"作为分隔符)

  • 单词"success";
  • Cookie名称;
  • Cookie值。

备注。 “1C:Предприятие”系统对网站管理系统的所有后续请求都包含在请求头中的Cookie名称和值。

B. 网站请求参数

接下来是以下类型的请求:
http://<网站>/<路径> /1c_exchange.php?type=catalog&mode=init

作为回应,网站管理系统发送两行

1. zip=yes,如果服务器支持zip格式的交换 - 在这种情况下,在下一步中,文件应打包为zip格式
或者
zip=no - 在这种情况下,在下一步中,文件不打包,每个文件单独传输。

2. file_limit=<数字>,其中 <数字> - 单个请求允许传输的最大文件大小(以字节为单位)。如果“1C:Предприятие”系统需要传输更大的文件,则应将其分割成片段。

C. 导出交换文件到网站

然后,“1C:Предприятие”通过以下参数类型的请求
http://<网站>/<路径> /1c_exchange.php?type=catalog&mode=file&filename=<文件名>
将交换文件以CommerceML 2格式导出到网站,通过POST发送文件内容或其部分。

在文件成功写入的情况下,网站管理系统返回字符串success

D. 数据逐步加载

最后一步是通过“1C:Предприятие”的请求以以下参数类型逐步加载数据http://<网站>/<路径> /1c_exchange.php?type=catalog&mode=import&filename=<文件名>

在加载过程中,网站管理系统可能以以下几种方式之一回应。

1. 如果第一行包含单词progress - 这意味着需要再次发送相同的请求。在这种情况下,第二行将返回当前处理状态、已加载数据量、导入状态等。

2. 如果返回包含单词success的字符串,这意味着文件处理成功完成的消息。

注意。 如果在处理请求过程中发生错误,则网站管理系统响应的第一行将包含单词“failure”,接下来的行将描述在处理请求过程中发生的错误。
如果发生无法处理的内核产品错误或SQL查询错误,则将返回HTML代码。

文件导出示例

商品信息的XML格式。
价格信息的XML格式.

订单信息交换

网站上的订单被上传到“1С:企业”系统。

处理订单的操作顺序

1. 订单在网站上完成

2. 在将订单传输到“1С:企业”系统时,订单将被设置为“网站订单”类别。
在“1С:企业”系统中创建订单时,记录订单号和日期,这些信息与网站上的订单匹配。根据设置,通过纳税人识别号或名称搜索合作伙伴。

3. 在加载订单时,将搜索与合作伙伴的合同。合同将在与客户存在的合同中搜索,具有按订单进行相互结算的标志(按设置的加载组织)。如果没有找到任何合同,则创建一个新的合同。

4. 在加载订单时,将加载从网站传输的所有属性。属性将在“1С:企业”系统中按名称搜索。如果没有找到具有该名称的属性,则将创建一个新的属性,其值类型为字符串或数字。

5. 订单可以在“1С:企业”系统中进行修改,此时修改将上传到网站

6. 如果订单在“1С:企业”系统中支付或发货,则只有在操作完全完成(全额支付和全额发货)时,订单的支付和发货状态才会上传到网站。在此之前,订单被视为未支付和未发货。

7. 在“1С:企业”系统中尝试更改已支付或已发货的订单时,网站上的订单不会作为更改上传。用户将收到有关此消息的通知。

8. 在每次将订单上传到网站后,网站端确定其类别的值(类别的链接)。这些值在“1С:企业”系统中设置,与网站上的订单分配的值相同

A. 会话开始

数据导出从“1C:Предприятие”系统发送以下类型的http请求开始
http://<网站>/<路径> /1c_exchange.php?type=sale&mode=checkauth.

作为回应,网站管理系统向“1C:Предприятие”系统发送三行(使用换行符"\n"作为分隔符)

  • 单词"success";
  • Cookie名称;
  • Cookie值。

备注。 “1C:Предприятие”系统对网站管理系统的所有后续请求都包含在请求头中的Cookie名称和值。

B. 会话参数的确认

接下来是以下类型的请求:
http://<网站>/<路径> /1c_exchange.php?type=sale&mode=init

作为回应,网站管理系统发送两行

1. zip=yes,如果服务器支持zip格式的交换 - 在这种情况下,在下一步中,文件应打包为zip格式
或者
zip=no - 在这种情况下,在下一步中,文件不打包,每个文件单独传输。

2. file_limit=<数字>,其中 <数字> - 单个请求允许传输的最大文件大小(以字节为单位)。如果“1C:Предприятие”系统需要传输更大的文件,则应将其分割成片段。

C. 从网站获取交换文件

然后向网站发送以下类型的请求
http://<网站>/<路径> /1c_exchange.php?type=sale&mode=query.

网站以CommerceML 2格式传输订单信息。在成功接收和记录订单后,“1С:企业”将向网站发送以下类型的请求:
http://<网站>/<路径> /1c_exchange.php?type=sale&mode=success

D. 将交换文件发送到网站

然后“1С:企业”系统向网站发送以下类型的请求:
http://<网站>/<路径> /1c_exchange.php?type=sale&mode=file&filename=<文件名>

该请求将文件交换文件上传到服务器,以POST的形式发送文件内容。

在成功记录文件后,网站管理系统将传输包含单词“success”的字符串。在接下来的行中,可能包含有关加载的注释。

注意。 如果在处理请求过程中发生错误,则网站管理系统响应的第一行将包含单词“failure”,接下来的行将描述在处理请求过程中发生的错误。
如果发生无法处理的内核产品错误或SQL查询错误,则将返回HTML代码。

交换信息文件的示例

网站订单的XML格式.
网站订单的XML格式.

此协议用于将“1С:企业”系统与“1С-Бит里克斯:网站管理”、“UMI.CMS”和其他系统集成。

测试和错误查找

此部分正在开发中

模块事件

beforeUpdateProduct

产品解析开始前的事件

afterUpdateProduct

产品解析完成后的事件

beforeUpdateOffer

解析提案开始前的事件

afterUpdateOffer

解析提案完成后的事件

beforeProductSync

解析所有产品开始前的事件

afterProductSync

解析所有产品完成后的事件

beforeOfferSync

解析所有提案开始前的事件

afterOfferSync

解析所有提案完成后的事件

afterFinishUploadFile

事件,在1C将档案或XML文件上传到您的网站后触发

afterExportOrders

从您的网站形成订单后的事件,在此方法中建议您实现状态更改或设置标志,以排除重复上传文档,因为它们将替换之前已上传的文档。