📜 ⬆️ ⬇️

The experience of integrating the Atol cash register with its own CRM trading system

Around the online cash register lately wild hype, July 1, 2019 ends the last delay, so I had to deal with this issue. Those who have 1C or another system should not strain themselves, but if you have your own samopisnaya system, then integration with online cash registers also falls on your shoulders.

My experience is useful for integration with Atol cash registers in the mode of data exchange over the network, your program can send data to the Atol web server both to the localhost and via the local network, you can even send from the AJAX browser, even from the server via CURL, therefore, no matter what language your corporate software is written in, everything is cross-platform.

The Atol 30f cash register came to my experiments - it is such a simple typewriter with a black box (FN), so it is appropriate when the entire ordering logic lies on the external software, and not on the software built into the cash register. In addition, devices of this type are relatively inexpensive compared to android counterparts.

Separately, I want to note that the “specialists” of some companies involved in support do not even know that Atol from version 10 has an embedded web server in the driver that accepts JSON tasks, moreover, this driver can also be installed on linux, judging by the number of ready-made solutions on the raspberries, I can assume that it can also be installed there, the installer for arm is present in the distribution kit of the 10th version of the driver.
')
The planned scheme is approximately the same - there is a CRM that spins on a server on the local network, it is opened from browsers, from the server side, PHP will be sent through curl with checks and printed at the checkout. And the cash register itself is connected to any computer on Windows on the same network.

They say that if you do not activate the cashier, then it can work in printer mode and print that check is invalid, but I could not verify this, I had to do penny sales and refund operations.

The driver of the tenth version is downloaded here .

Before installing, you need to install Java of the same bitness as the driver, otherwise the checkbox of the web server will not be available if you install the 64-bit CCP driver, then Java x64.

It seems that the logic needs to install a 64-bit driver on a 64-bit system, but some 32-bit software will not be able to work with it (it seems to be true for 1C if it is 32-bit).



At the end of the installation, there is a check mark - to configure the web server, if it is not checked, then you need to enter the browser at 127.0.0.1 : 16732 / settings, put a check mark “activate the server” and save.





After that, you need to restart the server via START-> ATOL-> restart ...

I also want to immediately warn you that if you start the web server, local applications will not be able to access the CCP, I was dying for a long time, installed the driver, started the driver test, and he tells me that the port is busy and everything, I called technical support for the local vendor, they said, we don’t know what to do, then overloaded the computer ten times, reinstalled the driver, nothing helps.

In general, after you activated and restarted the server, and before that you turned off the server and checked the plain text printing using the supplied utility or just checked the connection, you can proceed.

This web service does not have any password protection, so you need to immediately configure Windows Firewall or other software so that only the necessary computers can access on port 16732, in my situation it is the server on which CRM is spinning.

Communication with the web service is generally a separate topic, very interesting ...

  1. We generate unique uuid for the task
  2. We send the task by the POST method
  3. We are dabbling on the web service, waiting for the result of the task with our UUID, it may be that our task will have a wait status for a few seconds, and an error may occur if something is wrong in the request ...

And then I will give a working version, it is suitable for those situations where payment is only one method, and not so much of cash and part of cashless, the tax system is used by default, VAT is not calculated yet, I wanted to add a code, then upload it, but I think there are still people who need this information before July 1, than after. At once I will say that the class needs some work, a lot of raw, no error handling, everything is done in a couple of hours without reading the documentation, this code is more like an example and I advise you to study the documentation in detail and adapt it to your specific processes.

php code for an example of working with api (use only for educational purposes)
<?php Class AtolWebDriver { protected $addr="127.0.0.1",$port="16732"; public $timeout = 30; //  public $operator; function __construct($addr=false,$port=false) { if ($addr!==false) $this->addr=$addr; if ($port!==false) $this->port=$port; } public function CallAPI($method, $data,$_url="/requests") { $url = "http://".$this->addr.":".$this->port.$_url; $curl = curl_init($url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl,CURLOPT_TIMEOUT, $this->timeout); $headers = ['Content-Type: application/json']; curl_setopt($curl,CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); $resp = curl_exec($curl); $data = json_decode($resp,1); $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); $res= [$data,$code,$resp]; print_r($res); return $res; } //   public function get_res($uuid) { $ready = false; $cnt=0; $res_url = '/requests/'.$uuid; while (!$ready && ++$cnt<60) { usleep(500000); // ,     list($res,$code,$resp) = $this->CallAPI('GET',[],$res_url); $ready = ($res['results'][0]['status'] == 'ready'); if ($ready) return $res; } return false; //    } //  public function add_req($uuid,$req) { return $this->CallAPI('POST', ['uuid'=>$uuid,'request'=>$req]); } //  id   public function gen_uuid() { return exec('uuidgen -r'); } //      public function atol_task($type,$req=[]) { $req['type'] = $type; $uuid = $this->gen_uuid(); $req = $this->add_req($uuid,$req); if ($req[1]!='201') return false; //  $res = $this->get_res($uuid); //  if ($res===false || !isset($res['results'][0])) return false; return $res['results'][0]; } /*    */ //  public function get_shift_status() { $res = $this->atol_task('getShiftStatus'); if ($res===false) return false; //closed / opened / expired return $res['result']['shiftStatus']['state']; } //  public function open_shift() { $status = $this->get_shift_status(); //e ,    if ($status=="expired") $this->close_shift(); if ($status=="opened") return "    "; $res = $this->atol_task('openShift',['operator'=>$this->operator]); } //  public function close_shift() { $status = $this->get_shift_status(); if ($status=="closed") return "    "; $res = $this->atol_task('closeShift',['operator'=>$this->operator]); } public function items_prepare($items) { $res_items = []; $summ = 0; while ($item = array_shift($items)) { $res_item = $item; if (!isset($item['type'])) $res_item['type']="position"; if (isset($item['price']) && isset($item['quantity'])) { $res_item['amount'] = $item['price']*$item['quantity']; $res_item['tax'] = ['type'=>'none']; $summ+=$res_item['amount']; } $res_items[] = $res_item; } return [$res_items,$summ]; } // sell,  sellReturn public function fiskal($type_op="sell",$items,$pay_type="cash") { $data = []; $data['operator'] = $this->operator; $data['payments'] = []; list($data['items'],$summ) = $this->items_prepare($items); //+++       $data['payments'][] = ['type'=>$pay_type,'sum'=>$summ]; $res = $this->atol_task($type_op,$data); } } //  ip   web-  ,      $atol = new AtolWebDriver('192.168.100.10'); //    $atol->operator = ['name'=>'.']; //       $items = []; $items[] = ['name'=>' ','price'=>0.7,'quantity'=>1]; $items[] = ['name'=>' ','price'=>0.4,'quantity'=>1]; //  $atol->open_shift(); //  $atol->fiskal("sell",$items); sleep(10); // ,     //     , ..    $atol->fiskal("sellReturn",$items); //     sleep(20); // ,   $atol->close_shift(); 


There are some flaws that I will correct.

  1. Rounding fractions when calculating the amount, you need to round to kopecks, otherwise you can get 1.000000001 or 0.999999999
  2. With the correct writing of the rest of the program logic, this usually does not occur, but during the tests I found myself finding the task to return the result error, and I was waiting for the ready

Well, in the process of introducing I am afraid to catch many more mistakes, for example, if the task hangs for a long time in the wait status, then it is better to remove it from the queue, otherwise subsequent tasks will hang for a few minutes, I caught such a glitch once, I did not hope that it would print and here I sit, but it’s hop and printed two checks in a row sent earlier ...

In general, it is possible to collect acquiring services from the site in the future, if there are no online checks in them, until it was decided what kind of acquiring to screw on. But this decision, more likely as an idea for a decision, time will tell how this cash register will take root.

Warning , for those who have not read the article carefully and are not very competent in the security issue - this web service does not have encryption (https), does not have authorization , even if it is used only in the local network - set up protection for access to the port.

Source: https://habr.com/ru/post/457684/


All Articles