Данный модуль не путать с iKKM API, так как это совершенно другой модуль и функционал. Основная идея заключается в том, что сам iKKM является инициатором обмена данными, и используется как кассовый и банковский терминал без дополнительного оборудования.
Выберите подходящую для вас логику работы:
- Отправка чеков на сервер: после каждой регистрации или при закрытии смены.
- Получение справочника товаров: весь справочник товаров или онлайн при каждой регистрации.
JSON отправляемый на сервер:
{ "DocumentType": "SingleShiftExport", "DocumentsCount": "4", "PosDetails": { "factorySN": "000117184200028", "posRegNum": "0000" }, "ShiftAbout": { "cashierID": "166", "shiftCloseTime": "2020-07-03 23:05:54", "shiftId": "27", "shiftOpenTime": "2020-07-02 01:01:45" }, "ShiftData": [ { "chequeHeader": { "cheqDate": "2020-07-02 01:01:45", "cheqType": "sale", "chequeId": "229" }, "chequeTable": [ { "barcode": "00000000", "code": "00000000", "price": "17888987.00", "qty": "1.00", "section": "1", "sum": "17888987.00" } ], "payments": [ { "income": "17888987", "type": "cash" } ] }, { "chequeHeader": { "cheqDate": "2020-07-02 01:02:50", "cheqType": "sale", "chequeId": "230" }, "chequeTable": [ { "barcode": "", "code": "1", "price": "17888987.00", "qty": "1.00", "section": "1", "sum": "17888987.00" } ], "payments": [ { "income": "17888987", "type": "cash" } ] } ..... .... .. ] } ] }
Структура на GoLang:
type Item struct { DocumentType string `json:"DocumentType"` DocumentsCount string `json:"DocumentsCount"` PosDetails struct { FactorySN string `json:"factorySN"` PosRegNum string `json:"posRegNum"` } `json:"PosDetails"` ShiftAbout struct { CashierID string `json:"cashierID"` ShiftCloseTime string `json:"shiftCloseTime"` ShiftID string `json:"shiftId"` ShiftOpenTime string `json:"shiftOpenTime"` } `json:"ShiftAbout"` ShiftData []struct { ChequeHeader struct { CheqDate string `json:"cheqDate"` CheqType string `json:"cheqType"` ChequeID string `json:"chequeId"` } `json:"chequeHeader"` ChequeTable []struct { Barcode string `json:"barcode"` Code string `json:"code"` Price string `json:"price"` Qty string `json:"qty"` Section string `json:"section"` Sum string `json:"sum"` } `json:"chequeTable"` Payments []struct { Income string `json:"income"` Type string `json:"type"` } `json:"payments"` } `json:"ShiftData"` }
- пример ответа от сервера:
/// Примеры ответов от сервера { "DocumentType" : "SingleShiftExport" или "SaveAllDocumentResult", // тип обработанного документа "Result": "success", // success - удачно // error - не продолжать // warning - просто показать на экране сообщение из ErrorText, но считается как успех. "ErrorText": "" // если есть ошибка или предупреждение. }
- пример ответа GoLang:
c.JSON(200, gin.H{ "Result": "success", // success | error | warning "ErrorText": "none", "DocumentType": "SingleShiftExport", })
- Отправка данного запроса возможна только если нет открытых смен, нет очереди в ОФД
- После получения success, удалить все данные ShiftData
POST запроса: http://[url-журнал-документов]/SaveAllDocuments [url-журнал-документов] - адрес сервера и URL настраивается на iKKM в меню Настройки - Импорт - журнал
Пример удачного GET запроса:
http://[url-spravochnik-1c]/GetPriceList?ikkmserial=11700012233 [url-spravochnik-1c] - адрес сервера и URL настраивается на iKKM в меню Настройки - Импорт - Справочник товаров
http://[url-spravochnik-1c]/GetPriceList?ikkmserial=11700012233 [url-spravochnik-1c] - адрес сервера и URL настраивается на iKKM в меню Настройки - Импорт - Справочник товаров
Ответ в UTF-8 JSON:
{ "DocumentType" : "PriceList", // Нужен на будущее, если появятся доп. экспортированные док-ты "ItemsCount": "1", // Количество загружаемых элементов "Items": [ // массив всех элементов { "ID": "123", // from 1c ([a-zA-Z0-9]{1,128}) "Name": "Kafe with Milk", // max 256 (UTF-8) [а-яА-Я a-zA-Z0-9 \n\r!:?.,+*&$#@%=_;////]{1,256} "Price": "1002", // digits, delmitter .(dot) "Tax": "12", // digits , delmitter .(dot) "Barcode": "1234567890" // max 13 digits, only digits (\\d{10-13}) // Тип элемента - Услуга, Товар, Прочее. [на будущее] // Единица измерения - Литры, Штуки. [на будущее] // Номер секции для фиск. [на будущее] } //, {....} ], "Result": "success", // error - не продолжать | warning "ErrorText": "error text" // если есть ошибка или предупреждение. }
{ "chequeHeader": { "cashierID": "166", "cashierName": "Алия кассир", "cheqDate": "2017-09-14 15:36:05", "cheqType": "sale", "chequeId": "1138", "shiftId": "191" }, "chequeTable": [{ "code": "222", "barcode": "112121212", "price": "2550.00", "qty": "1.00", "section": "1", "sum": "2550.00" }, { "code": "none", "barcode": "112121212", "price": "400.00", "qty": "2.00", "section": "1", "sum": "800.00" }], "payments": [{ "income": "2988", "type": "cash" }, { "income": "1000", "type": "bank" }, { "outcome": "638.00", "type": "cash" }], "posDetails": { "factorySN": "000118164600196", "posRegNum": "000000000006" } }
формат ответа см - “Выгрузка всех продаж за смену (POST)”
При каждой регистрации, если товара нет в базе, iKKM отправляет запрос на сервер. После этого кэширует ( записывает в бд) данный товар для дальнейшего использования. Удаление (каждый раз, раз в смену, никогда) настраиваются в свойствах импорта iKKM.
http://[url-spravochnik-1c]/GetByBarcode?barcode=4606260002219
Пример сервера на GoLang:
func main() { r := mux.NewRouter() r.HandleFunc("/", Hello) r.HandleFunc("/GetByBarcode", BarCodeHandler).Methods("GET") http.Handle("/", r) fmt.Println("Starting up on 8080") log.Fatal(http.ListenAndServe(":8080", nil)) } func Hello(w http.ResponseWriter, req *http.Request) { fmt.Fprintln(w, "Hello world!") } func BarCodeHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) json := simplejson.New() json.Set("ID","ЦБ-00004019") json.Set("Name","Какао 100 г") json.Set("Barcode","4606260002219") json.Set("Measure","шт") json.Set("Price","255") json.Set("Tax","12") json.Set("Result","success") payload, err := json.MarshalJSON() if err != nil { log.Println(err) } w.Header().Set("Content-Type", "application/json") w.Write(payload) }
Отработка ошибок
func BarCodeHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) barcode := r.URL.Query().Get("barcode") json := simplejson.New() switch sampleScenarios := barcode; sampleScenarios { case "11144444": // sample 1 json.Set("Result", "success") json.Set("ID", "111") json.Set("Name", "Какао 100 г") json.Set("Price", "255") json.Set("Tax", "12") json.Set("Barcode", "11144444") case "22244444": // sample 2 (другой налог) json.Set("Result", "success") json.Set("ID", "222") json.Set("Name", "Beer Paulainer Длинное наименование названия товара с описанием #2823 арт 123.567 конец") json.Set("Price", "2550") json.Set("Tax", "3") json.Set("Barcode", "22244444") case "33344444": // sample 3(ответ с тормозами) json.Set("Result", "success") json.Set("ID", "333") json.Set("Name", "Slow Beer") json.Set("Price", "550") json.Set("Tax", "3") json.Set("Barcode", "33344444") time.Sleep(5000 * time.Millisecond) case "00044444": // sample 4(нули в коде и штрихкоде) json.Set("Result", "success") json.Set("ID", "004") json.Set("Name", "ZERO Beer описание товара со средней длиной товара") json.Set("Price", "2870") json.Set("Tax", "3") json.Set("Barcode", "00044444") case "55544444": // sample 5(кривой налог) json.Set("Result", "success") json.Set("ID", "005") json.Set("Name", "BAD Beer") json.Set("Price", "2870") json.Set("Tax", "36") json.Set("Barcode", "00044444") case "66644444": // sample 6(цена с тиинками) json.Set("Result", "success") json.Set("ID", "006") json.Set("Name", "Float Beer") json.Set("Price", "214.23") json.Set("Tax", "12") json.Set("Barcode", "66644444") case "77744444": // sample 7 (кривой json) w.Header().Set("Content-Type", "application/json") w.Write([]byte("{ME is very:+ broken JSON}")) default: // ошибка по умолчанию json.Set("Result", "error") json.Set("ErrorText", "Bad bar code! Плохой!") } payload, err := json.MarshalJSON() if err != nil { log.Println(err) } w.Header().Set("Content-Type", "application/json") w.Write(payload) fmt.Printf("-> barcodeReq: %s, result %s\n", barcode, json.Get("Result")) }