将Atol收银台与自己的CRM交易相集成的经验

最近在网上票房周围,令人兴奋的是,在2019年7月1日,最后一次推迟结束了,所以我不得不处理这个问题。 拥有1C或其他系统的人尤其不能承受压力,但是,如果您拥有自己的手写系统,那么与在线收银机的集成也将由您自己承担。

我的经验对于在网络数据交换模式下与Atol收银台集成非常有用,您的程序可以将数据发送到本地主机和本地网络上的Atol Web服务器,甚至可以通过AJAX浏览器甚至通过CURL从服务器发送数据,因此,无论您的公司软件使用哪种语言编写,所有内容都是跨平台的。

我遇到过Atol 30f售票处-这是一台带黑匣子(FN)的简单打字机,适用于所有订购逻辑都在外部软件上而不是在收银员内置软件上使用的情况。 此外,与android同类产品相比,此类设备相对便宜。

我还要指出,参与支持的一些公司的“专家”根本不知道Atoll 10版在驱动程序中具有内置的Web服务器,该服务器可以接受JSON作业,此外,该驱动程序还可以安装在Linux上,根据树莓派上现成的解决方案的数量,我可以假设它也可以安装在该版本中,在第10版驱动程序的发行版中,安装了arm安装程序。

计划的方案是这样的-本地网络中的服务器上运行着CRM,它是从浏览器中打开的,从服务器端开始,支票将通过curl发送到PHP并在收银机上打印。 收银台本身可以连接到同一网络上Windows上的任何计算机。

他们说,如果您不激活收银员,那么它可以在打印机模式下工作并打印支票无效,但我无法验证,我必须进行零钱销售和退货。

第十版的驱动程序在这里下载。

在安装之前,您需要安装与驱动程序具有相同位深度的Java ,否则,如果安装了64位KKT驱动程序,则安装Java x64,则复选框Web服务器将不可用。

从逻辑上看,您需要在64位系统上安装64位驱动程序,但是某些32位软件将无法使用它(例如,如果是32位,则适用于1C)。



安装结束时,会有一个选中标记-配置Web服务器,如果尚未安装,则需要以127.0.0.1:16732 /设置进入浏览器,选中“激活服务器”框并保存。





之后,您需要通过START-> ATOL-> restart重新启动服务器。

我还想立即警告您,如果您启动Web服务器,则本地应用程序将无法访问CCP,我辛苦了很长时间,安装了驱动程序,运行了Cct驱动程序测试,他告诉我端口很忙,仅此而已,我打电话给了本地卖方的技术支持,他们说我们不知道该怎么办,然后我使计算机超载了十次,重新安装了驱动程序,没有任何帮助。

通常,在激活并重新启动服务器之后,然后再关闭服务器并通过提供的实用程序检查纯文本的打印,或者仅检查连接,然后即可继续进行。

该Web服务没有任何密码保护,因此您需要立即配置Windows防火墙或其他软件,以便只有必要的计算机才能访问端口16732,在我的情况下,这是运行CRM的服务器。

与Web服务的通信通常是一个单独的主题,非常有趣...

  1. 为工作生成唯一的uuid
  2. 我们使用POST方法发送任务
  3. 我们渴望一个Web服务,用我们的UUID等待任务的结果,这可能是几秒钟后我们的任务将处于等待状态,或者如果请求中出现问题,则可能会发生错误...

然后我给出一个可行的版本,它适用于仅是一种付款方式,而现金和非现金不多的情况,它还使用默认的税制,还没有计算增值税,我想添加代码,然后将其分发出去,但是我认为仍然有人需要在7月1日之前而不是之后的信息。 我必须马上说,该类需要改进,大量原始操作,没有错误处理,所有工作都是在几个小时内完成的,而无需考虑文档的阅读,该代码更多地作为示例,我建议您详细研究文档并使其适合您的特定流程。

用于使用api的示例的php代码(仅用于教育目的)
<?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(); 


我会修复一些缺陷

  1. 将金额四舍五入时,需要四舍五入为美分,否则可以得到1.000000001或0.999999999
  2. 使用其余程序逻辑的正确拼写,通常不会发生这种情况,但是在测试过程中,我发现任务返回了错误结果,我在等待准备就绪。

嗯,在实施过程中,我恐怕会遇到更多错误,例如,如果任务在等待状态下长时间挂起,那么最好将其从队列中删除,否则后续任务将挂起几分钟,我遇到了一次小故障,我不希望它会打印出来我坐在这里,但是它跳了一下,并立即打印了先前发送的连续两张支票...

通常,如果他们没有在线检查,将来可能会从该站点收集并购,直到您决定搞砸哪个购并。 但是解决方案是,作为解决方案的主意,时间会证明这个票房将如何扎根。

警告 ,对于那些不专心阅读文章并且在安全性问题上不太能干的人- 此Web服务没有加密(https),没有授权 ,即使仅在本地网络上使用也是如此-配置对端口访问的保护。

Source: https://habr.com/ru/post/zh-CN457684/


All Articles