自2017年7月1日起,在俄罗斯联邦领土上必须强制使用收银机(KKM)将其所有交易直接发送至联邦税务局。 所谓在线票房。 这项创新的介绍已经在所有方面,或者至少在所有严肃的方面都进行了讨论。 联邦法律是否可以没有太严肃的一面,以及它赋予我们的创造力的余地-这已经被削减了。
现在,所有KKM都会将我们的交易通知联邦税务局,联邦税务局已经发布了一个特殊的移动应用程序(
Google Play ,
App Store ),以确保每个在线收银员的诚实,允许用户检查提供给他的任何支票,并将支票告知主管当局。失败了
当我听说有人开始收集大量信息时,我认为与潜在收益无关,而与实施成本无关。 甚至没有那个大哥在看着。 在我的脑海中,立即绘制出可以过滤和连接的标志,可以扭曲的立方体,可以构建的图表等。 我们可以以某种方式坚持从卖方到州的数据流吗? 我们可以。 (以小弓的形式,FTS应用程序还提供了获得此支票本身的电子版本的机会。)
当我发现这个机会时,我着火了。 仔细查看应用程序的功能并不会令我失望:不仅可以使用html或png,而且可以使用json获得检查。
事实是,我试图保持所有支出。 我尝试定期执行此操作,但是,当然,事实证明,我连续几个星期都忘记这样做。 并开始沉浸在过去并填充白色斑点的Ericksonian催眠会议。
正是从这一痛苦的过程中,联邦税务局将帮助我们摆脱困境。
从理论上讲,事实证明,您不必分析月底的多家银行的银行对帐单和一堆纸质支票(尝试了解所有资金再次合并的位置,而是可以分析附件中json框中的字母山。 前景也很一般,但与第一个不同,它更适合自动化。
因此,进行购买后,我们可以通过邮件接收JSON格式的支票。 此外,从理论上讲,为此购买时,我们甚至不需要联邦税务局的应用程序:我们可以在应用程序中预先生成带有邮件二维码的名片,并在购买时出示给收银员。 然后,我们可以要求以电子支票代替纸质支票,这将立即落入邮件中。 与在线购物一样。
但是,即使是联邦税务局也直接写了这个功能-“不要自欺欺人”。 并非所有的KKM都支持它。 即使在KKM支持的情况下,收银员本身也不是完全支持它。 所以现在这是为了坚强的精神。
收到邮件中的支票后,我们只需要对它进行自动化分析,并为我们方便地将其卸载。
您需要选择将所有这些内容卸载的位置,以便进一步使用它。
我不知道您的状况,但是个人使用这些雇员或这些国有雇员,因此,我总是将他们的数据导出以进行分析,以使用良好的旧Excel。 无论开发人员预先在产品中包括什么图形和图表,他们都将永远无法预测我想从数据中提取的一切。 与月相,分组,除以今天的数字相比,要考虑哪些交易,哪些交易要忽略... Excel可以完成所有这些工作。
此外,如果我们将Excel放在OneDrive中,则可以通过Web完美地访问它,包括从移动OS中访问它。 而且,与GoogleDrive不同,公式将在此处完美运行,包括使我们能够为每次购买的类别和子类别组织级联下拉列表的公式。
小事情是处理解析器。 我们需要一种从邮箱接收带有附件的字母,解析json附件并将结果写入OneDrive中的Excel平板电脑的机制。
在理想的世界中,我认为此解析器就像是
IFTTT的一个步骤。 这样,我们的解决方案便可以完全在网络上运行,而无需用户提出任何要求(因为我们谈论的是理想世界,因此联邦税务局的“名片”可以在其中完美运行)。
但是,立即了解街上的人们如何为IFTTT写下自己的脚步-并了解这是否完全可能。 我失败了。 如果有人可以提出解释性指南或替代平台,我将非常感谢。
由于网络解决方案效果不佳,因此我们在桌面上实现了解析器的一个链接。 在
NORBIT,我正在实施Dynamics CRM,因此Microsoft堆栈对我来说是最熟悉的。 是的,我们已经开始通过选择Excel和OneDrive使用它。 我们实现了Outlook插件,在其中放置了所需的所有逻辑。
在这里,我走了阻力最小的道路。
首先,我采用了从FTS接收到的JSON并将其提供给
json2csharp.com 。 得到了反序列化的类结构:
public class Item { public string name { get; set; } public int nds18 { get; set; } public int price { get; set; } public double quantity { get; set; } public int sum { get; set; } public int? nds10 { get; set; } } public class Receipt { public List<Item> items { get; set; } public string retailPlaceAddress { get; set; } public string userInn { get; set; } public int requestNumber { get; set; } public int nds18 { get; set; } public string fiscalDriveNumber { get; set; } public string user { get; set; } public string @operator { get; set; } public int fiscalDocumentNumber { get; set; } public int taxationType { get; set; } public int ecashTotalSum { get; set; } public string kktRegId { get; set; } public DateTime dateTime { get; set; } public int operationType { get; set; } public int cashTotalSum { get; set; } public int receiptCode { get; set; } public int nds10 { get; set; } public int totalSum { get; set; } public int shiftNumber { get; set; } public int fiscalSign { get; set; } }
现在,您需要收到一封信,对上面获得的类的附件进行反序列化,然后将它们转换为XLSX。
我使用Newtonsoft.Json进行反序列化,并使用ClosedXML进行Excel编写。 随后,事实证明,可能不必费心直接写XLSX,而是安静地以CSV格式写-由于某些原因,在处理具有数据透视表的文件时,ClosedXML崩溃。 因此,到目前为止的统计信息必须在单独的前文件中取出,并从插件中卸载作为数据源。
插件本身非常简单。 为了不处理所有传入的信件,我打开了一个专用于检查的单独邮箱,并检查该信件是否已送达他。 接下来,当然,您需要将其放入所有文件夹地址之类的可配置设置中。
void Items_ItemAdd(object Item) { Outlook.MailItem mail = (Outlook.MailItem)Item; if (Item != null) { if (mail.Attachments.Count == 1 & mail.To.Equals("my@mail.address")) { Outlook.Attachment attach = mail.Attachments[1]; string path = "C:\\_Data\\_tmp\\" + attach.FileName; attach.SaveAsFile(path); string text = System.IO.File.ReadAllText(path); System.IO.File.Delete(path); List<TableRow> objectList = GetBillsData(text); WriteBillsToXLSX(objectList); } } } private static void WriteBillsToXLSX(List<TableRow> objectList) { var workbook = new XLWorkbook(tablePath); var ws = workbook.Worksheet("Products"); int startrow = ws.LastRowUsed().RowNumber(); if (ws.CellsUsed().Count() != 0) startrow = ws.CellsUsed().Last().Address.RowNumber; foreach (var item in objectList) { startrow++; ws.Cell(startrow, 1).Value = item.dateTime; ws.Cell(startrow, 2).Value = item.sum; ws.Cell(startrow, 3).Value = item.quantity; ws.Cell(startrow, "J").Value = item.user; ws.Cell(startrow, "S").Value = item.name; } workbook.SaveAs(tablePath); } private static List<TableRow> GetBillsData(string bill) { Receipt doc = JsonConvert.DeserializeObject<Receipt>(bill); List<TableRow> objectList = new List<TableRow>(); foreach (var item in doc.items) { objectList.Add(new TableRow(item, doc)); } return objectList; }
从JSON到表行的所有数据转换都已移至TableRow构造函数。
现在,完成购买后,我们就可以扫描支票了,所有支票本身都将落入我们位于云中的文件中。 我们可以在这里看到此文件,而无需离开收银台。 在支持现代浏览器的任何操作系统上,我们都可以查看。
剩下的只是放下已加载行的类别和子类别,您可以构建任何令我们高兴的分析。 仅需要几行代码,如果文件中已有一行具有相同描述且之前已填写了类别,则该插件将学习如何为行添加类别/子类别。
本质上就是这样的数据循环。