API УКМ 5 доступно на кассовом сервере. Порт: 29017.
Описание API актуально для версии API 1.0, кассового сервера версии 1.25.
Совместимость версий API гарантируется в пределах мажорной версии. Т.е. версии 1.0, 1.1, 1.2 и т.д. совместимы, но версии 1.1 и 2.3, например, нет.
Серверная архитектура кассовой системы диктует определенные требования к правилам загрузки информации из товаро-учетной системы: если во внешней товаро-учетной сстеме изменяется объект (или создается новый / удаляется ранее существовавший), то информация об этом должна быть передана кассовому серверу (API) только один раз. Далее кассовой сервер организует доставку этой информации до касс, к которым относится объект.
Объекты, которые выгружает торгово-учетная система, могут быть двух типов:
Объекты, общие для всех касс:
- справочник налогов (/api/v1/import/taxes и /api/v1/import/taxGroups);
- группы товаров (товарная иерархия) (/api/v1/import/groupItems);
- товары (включая шрихкоды) (/api/v1/import/items);
- дополнительные параметры товаров (/api/v1/import/itemProperties);
- пик-листы (/api/v1/import/picklists);
- поставщики/продавцы (/api/v1/import/legalEntities);
- товары поставщиков/продавцов (/api/v1/import/legalEntityItemContractors и /api/v1/import/legalEntityItemVendors, соответственно).
Объекты, общие для касс магазина:
- цены на товары (/api/v1/import/store/{id}/itemPrices);
- дополнительные цены на товары (/api/v1/import/store/{id}/AlternativeItemPrices);
- цены на штрихкоды (/api/v1/import/store/{id}/barcodePrices);
- кассиры (/api/v1/import/store/{id}/AlternativeItemPrices);
- продавцы-консультанты (/api/v1/import/store/{id}/sellers).
Надо иметь в виду, что загружаемый объект всегда должен содержать все его атрибуты: имеющаяся запись будет полностью заменена на новое значение. Если какой-то атрибут отсутствует в запросе, то, если он обязателен в соответствии со схемой (помечен значком *), то запрос не будет принят системой (возникнет сообщение об ошибке); если атрибут не обязателен, то его значение будет установлено в значение null. В том числе, это относится к атрибутам, содержащим множество значений. Например, в информации о товаре есть атрибут barcodes. При каждой выгрузке товара в атрибуте barcodes должны быть перечислены все штрихкоды для данного товара и прежний перечень будет полностью заменен на новый, в том числе и на пустой.
Если при загрузке объекта возникает ошибка, то не принимается весь пакет, а не только ошибочный объект.
В УКМ 5 поставщик может иметь признак, что он не является плательщиком НДС. В этом случае, касса использует специальную налоговую ставку. В противном случае, ставка НДС берется из товарного справочника. Такое упрощение было сделано сознательно, т.к. проблема может возникнуть только, если один и тот же поставщик реализует товары как по льготной ставке, так и по полной, что является редким случаем.
На текущий момент, в России существует только один налог, учитываемый в розничной торговле. Это НДС, имеющий 2 ставки: 10% и 20%.
Пример заполнения справочника групп налогов (таблица tax_group в базе данных):
Id (код группы) | Tax_id | Percent | Fp_code | Advanced_tax_id | Is_preferential | Примечание |
1 | 1 | 10 | 5 | false | НДС=10% | |
2 | 1 | 20 | 6 | false | НДС=20% | |
3 | 1 | 0 | false | НДС=0% | ||
4 | 1 | 0 | true | НДС не облагается | ||
5 | 1 | 10 | false | 10/110 | ||
6 | 1 | 20 | false | 20/120 |
Товары со ставкой НДС в 10% в торговой системе привязаны к группе с id=1.
Товары со ставкой НДС в 20% в торговой системе привязаны к группе с id=2.
Если в товарном справочнике в торговой системе есть товары, облагаемые по ставке НДС=0 (не путать с «НДС не облагается»!), то:
- в справочнике должна быть группа со ставкой НДС=0% и значением Is_preferential=false (в данном примере – id=3).
Если предполагается продажа товара без расчета НДС (например, продажа на кассах юр. лица, освобожденного от уплаты НДС), то:
- в справочнике должна быть группа, «отвечающая» за ставку «НДС не облагается» (в данном примере – id=4) с установленным признаком Is_preferential=true;
- независимо от того, какая группа указана у товара, в чеке он будет зарегистрирован с группой id=4.
Если предполагается получение на кассе предоплаты за товары, то:
- в справочнике должны быть группы, «отвечающие» за расчетные ставки (в данном примере – id=5 и 6, соответственно);
- для групп с «обычными» ставками должны быть указаны соответствующие им расчетные группы (в параметре Advanced_tax_id);
- при получении предоплаты за товар с группой id=2, товар будет зарегистрирован в чеке с группой 6 (для группы id=2 указано значение Advanced_tax_id=6);
- при получении предоплаты за товар с группой id=1, товар будет зарегистрирован в чеке с группой 5 (для группы id=1 указано значение Advanced_tax_id=5).
Если предполагается получение на кассе авансовых платежей (например, продажа подарочного сертификата), то:
- в справочнике должна быть группа, «отвечающая» за расчетную ставку (в данном примере – id=6);
- товар, который регистрируется в чеке для получения аванса, должен иметь атрибут Аванс;
- если для SKU указана налоговая ставка с признаком Is_preferential=true, то с этой ставкой он и будет регистрироваться в чеке;
- если SKU продается в магазине, для которого задано, что он не является плательщиком НДС, то SKU регистрируется в чеке с налоговой группой, для которой установлено значение Is_preferential=true;
- если для SKU указана налоговая ставка с заполненным значением Advanced_tax_id (в справочнике налоговых групп), то SKU регистрируется с налоговой группой, указанной в Advanced_tax_id;
- если для SKU указана налоговая ставка с незаполненным Advanced_tax_id, то SKU регистрируется с указанной для него налоговой группой.
Следует помнить о том, что для правильной регистрации товаров в ККТ необходимо устанавливать соответствие между налоговыми группами в кассовой программе и в конкретных моделях ККТ. Установка соответствия происходит в разделе fiscalprinter настроек оборудования.
Например, для ККТ СП-801 и справочника налогов, приведенного выше, соответствие должно быть установлено следующим образом:
# Соответствие налога в ККТ СП и налоговой группы в УКМ 5
# Налоги в ККТ СП-801
# tax0 – НДС 20;
# tax1 – НДС 10;
# tax2 – НДС 0;
# tax3 – без НДС;
# tax4 – 20/120;
# tax5 – 10/110.
taxes: { tax0 = 2 tax1 = 1 tax2 = 3 tax3 = 4 tax4 = 6 tax5 = 5 } |
По мере развития продукта СуперМаг УКМ5, планируется реализация следующих параметров, формальное наличие которых в API-документации на текущий момент не означает, что они функционально реализованы:
/api/v1/import/store/{id}/barcodePrices
isPromoPrice – признак того, что торговая система проводит акцию на данный товар в данном магазине
dateTo – дата и время начала действия цены
dateFrom – дата и время окончания действия цены
/api/v1/import/store/{id}/itemPrices
isPromoPrice – признак того, что торговая система проводит акцию на данный товар в данном магазине
dateTo – дата и время начала действия цены
dateFrom – дата и время окончания действия цены
/api/v1/import/items
descr – подробное описание товара
/api/v1/import/itemProperties
showToCashier – показывать свойство на экране кассира
printOnReceipt – печатать значение свойства в чеке
/api/v1/import/taxGroups
fpCode – код налоговой группы в фискальном устройстве.
Экспорт продаж может происходить двумя способами:
1. Сервер УКМ 5 работает как клиент для сервера товаро-учетной системы. Т.е. в товаро-учетной системе должен быть REST API-сервис, который реализует следующую схему запросов:
/api/v1/export/receipt – Экспорт чеков. Этот метод должен быть реализован на внешнем сервере.
/api/v1/export/shift – Экспорт смены с чеками. Этот метод должен быть реализован на внешнем сервере.
/api/v1/export/moneyOperation – Экспорт операций с денежным ящиком. Этот метод должен быть реализован на внешнем сервере.
2. Сервер УКМ 5 работает как сервер для товаро-учетной системы, т.е. товаро-учетная система обращается к серверу УКМ 5 и получает нужную информацию:
/api/v1/export/receipt/{storeId}/{date} – Экспорт чеков по запросу за дату (по всем кассам магазина).
/api/v1/export/shiftWOReceipts/{storeId}/{date} – Экспорт смен без чеков по запросу за дату (по всем кассам магазина).
/api/v1/export/shift/{storeId}/{posId}/{date} – Экспорт конкретной смены (вместе с чеками) по запросу.
В обоих вариантах взаимодействия авторизация не требуется. Безопасность обеспечивается IT-службами клиента.
Для метода /api/v1/export/receiptPackage существует ряд запросов:
№ | Название запроса | Тип запроса | Параметры запроса | Код ответа | Тело ответа |
---|---|---|---|---|---|
1 | Выгрузка чеков с подтверждением | GET | 200 | Чеки со статусом выгрузки Невыгруженные чеки. Количество чеков в пачке ограничено параметром Размер пачки. | |
700 | Имеется блокировка на выгрузку. | ||||
500 | Ошибка, описание ошибки. | ||||
2 | Подтверждение получения и обработки пачки чеков | PUT | 200 | Ok. | |
500 | Ошибка, описание ошибки. | ||||
3 | Удаление блокировки | DELETE | 200 | Ok. | |
500 | Ошибка, описание ошибки. |
API УКМ 5 допускает использование кастомных кодов для обозначения различных средств оплаты. Для активации механизма мапирования кодов средств оплаты, необходимо обратиться к команде техподдержки УКМ 5.
Механизм мапирования фигурирует в выгружаемой информации по чеку (например, /api/v1/export/receiptPackage) и реализован через переменную pType:
paymentTypeMap: [ {externalId = 1, pType = "cash"}, {externalId = 2, pType = "card"}, {externalId = 3, pType = "certificate"}] |
Здесь pType может принимать следующие значения:
- cash – наличные;
- card – банковская карта;
- certificate – подарочный сертификат/подарочная карта;
- PayCard – платежная карта (не банковская);
- other – другие средства оплаты.
Если для pType задано значение, то для всех средств оплаты с данным pType значение Receipt.payments.paymentId заменяется на значение, указанное в параметре externalId.
Если мапирование не задано, то Receipt.payments.paymentId выгружается без изменения.
Внимание! Мапирование кодов средств оплаты не реализовано для запросов по выгрузке смен.
{"swagger":"2.0","info":{"description":"This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.","version":"1.0.6","title":"Swagger Petstore","termsOfService":"http://swagger.io/terms/","contact":{"email":"apiteam@swagger.io"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"}},"host":"petstore.swagger.io","basePath":"/v2","tags":[{"name":"pet","description":"Everything about your Pets","externalDocs":{"description":"Find out more","url":"http://swagger.io"}},{"name":"store","description":"Access to Petstore orders"},{"name":"user","description":"Operations about user","externalDocs":{"description":"Find out more about our store","url":"http://swagger.io"}}],"schemes":["https","http"],"paths":{"/pet/{petId}/uploadImage":{"post":{"tags":["pet"],"summary":"uploads an image","description":"","operationId":"uploadFile","consumes":["multipart/form-data"],"produces":["application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to update","required":true,"type":"integer","format":"int64"},{"name":"additionalMetadata","in":"formData","description":"Additional data to pass to server","required":false,"type":"string"},{"name":"file","in":"formData","description":"file to upload","required":false,"type":"file"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/ApiResponse"}}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet":{"post":{"tags":["pet"],"summary":"Add a new pet to the store","description":"","operationId":"addPet","consumes":["application/json","application/xml"],"produces":["application/json","application/xml"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"put":{"tags":["pet"],"summary":"Update an existing pet","description":"","operationId":"updatePet","consumes":["application/json","application/xml"],"produces":["application/json","application/xml"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"},"405":{"description":"Validation exception"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByStatus":{"get":{"tags":["pet"],"summary":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","operationId":"findPetsByStatus","produces":["application/json","application/xml"],"parameters":[{"name":"status","in":"query","description":"Status values that need to be considered for filter","required":true,"type":"array","items":{"type":"string","enum":["available","pending","sold"],"default":"available"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid status value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByTags":{"get":{"tags":["pet"],"summary":"Finds Pets by tags","description":"Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","operationId":"findPetsByTags","produces":["application/json","application/xml"],"parameters":[{"name":"tags","in":"query","description":"Tags to filter by","required":true,"type":"array","items":{"type":"string"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid tag value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}],"deprecated":true}},"/pet/{petId}":{"get":{"tags":["pet"],"summary":"Find pet by ID","description":"Returns a single pet","operationId":"getPetById","produces":["application/json","application/xml"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to return","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Pet"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"api_key":[]}]},"post":{"tags":["pet"],"summary":"Updates a pet in the store with form data","description":"","operationId":"updatePetWithForm","consumes":["application/x-www-form-urlencoded"],"produces":["application/json","application/xml"],"parameters":[{"name":"petId","in":"path","description":"ID of pet that needs to be updated","required":true,"type":"integer","format":"int64"},{"name":"name","in":"formData","description":"Updated name of the pet","required":false,"type":"string"},{"name":"status","in":"formData","description":"Updated status of the pet","required":false,"type":"string"}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"delete":{"tags":["pet"],"summary":"Deletes a pet","description":"","operationId":"deletePet","produces":["application/json","application/xml"],"parameters":[{"name":"api_key","in":"header","required":false,"type":"string"},{"name":"petId","in":"path","description":"Pet id to delete","required":true,"type":"integer","format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/store/order":{"post":{"tags":["store"],"summary":"Place an order for a pet","description":"","operationId":"placeOrder","consumes":["application/json"],"produces":["application/json","application/xml"],"parameters":[{"in":"body","name":"body","description":"order placed for purchasing the pet","required":true,"schema":{"$ref":"#/definitions/Order"}}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid Order"}}}},"/store/order/{orderId}":{"get":{"tags":["store"],"summary":"Find purchase order by ID","description":"For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions","operationId":"getOrderById","produces":["application/json","application/xml"],"parameters":[{"name":"orderId","in":"path","description":"ID of pet that needs to be fetched","required":true,"type":"integer","maximum":10,"minimum":1,"format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}},"delete":{"tags":["store"],"summary":"Delete purchase order by ID","description":"For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors","operationId":"deleteOrder","produces":["application/json","application/xml"],"parameters":[{"name":"orderId","in":"path","description":"ID of the order that needs to be deleted","required":true,"type":"integer","minimum":1,"format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}}},"/store/inventory":{"get":{"tags":["store"],"summary":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","operationId":"getInventory","produces":["application/json"],"parameters":[],"responses":{"200":{"description":"successful operation","schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"security":[{"api_key":[]}]}},"/user/createWithArray":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithArrayInput","consumes":["application/json"],"produces":["application/json","application/xml"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithList":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithListInput","consumes":["application/json"],"produces":["application/json","application/xml"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/{username}":{"get":{"tags":["user"],"summary":"Get user by user name","description":"","operationId":"getUserByName","produces":["application/json","application/xml"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be fetched. Use user1 for testing. ","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/User"}},"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}},"put":{"tags":["user"],"summary":"Updated user","description":"This can only be done by the logged in user.","operationId":"updateUser","consumes":["application/json"],"produces":["application/json","application/xml"],"parameters":[{"name":"username","in":"path","description":"name that need to be updated","required":true,"type":"string"},{"in":"body","name":"body","description":"Updated user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"400":{"description":"Invalid user supplied"},"404":{"description":"User not found"}}},"delete":{"tags":["user"],"summary":"Delete user","description":"This can only be done by the logged in user.","operationId":"deleteUser","produces":["application/json","application/xml"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be deleted","required":true,"type":"string"}],"responses":{"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}}},"/user/login":{"get":{"tags":["user"],"summary":"Logs user into the system","description":"","operationId":"loginUser","produces":["application/json","application/xml"],"parameters":[{"name":"username","in":"query","description":"The user name for login","required":true,"type":"string"},{"name":"password","in":"query","description":"The password for login in clear text","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","headers":{"X-Expires-After":{"type":"string","format":"date-time","description":"date in UTC when token expires"},"X-Rate-Limit":{"type":"integer","format":"int32","description":"calls per hour allowed by the user"}},"schema":{"type":"string"}},"400":{"description":"Invalid username/password supplied"}}}},"/user/logout":{"get":{"tags":["user"],"summary":"Logs out current logged in user session","description":"","operationId":"logoutUser","produces":["application/json","application/xml"],"parameters":[],"responses":{"default":{"description":"successful operation"}}}},"/user":{"post":{"tags":["user"],"summary":"Create user","description":"This can only be done by the logged in user.","operationId":"createUser","consumes":["application/json"],"produces":["application/json","application/xml"],"parameters":[{"in":"body","name":"body","description":"Created user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"default":{"description":"successful operation"}}}}},"securityDefinitions":{"api_key":{"type":"apiKey","name":"api_key","in":"header"},"petstore_auth":{"type":"oauth2","authorizationUrl":"https://petstore.swagger.io/oauth/authorize","flow":"implicit","scopes":{"read:pets":"read your pets","write:pets":"modify pets in your account"}}},"definitions":{"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"type":{"type":"string"},"message":{"type":"string"}}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Category"}},"Pet":{"type":"object","required":["name","photoUrls"],"properties":{"id":{"type":"integer","format":"int64"},"category":{"$ref":"#/definitions/Category"},"name":{"type":"string","example":"doggie"},"photoUrls":{"type":"array","xml":{"wrapped":true},"items":{"type":"string","xml":{"name":"photoUrl"}}},"tags":{"type":"array","xml":{"wrapped":true},"items":{"xml":{"name":"tag"},"$ref":"#/definitions/Tag"}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"xml":{"name":"Pet"}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Tag"}},"Order":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"petId":{"type":"integer","format":"int64"},"quantity":{"type":"integer","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean"}},"xml":{"name":"Order"}},"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"integer","format":"int32","description":"User Status"}},"xml":{"name":"User"}}},"externalDocs":{"description":"Find out more about Swagger","url":"http://swagger.io"}} |