Все записи автора Павел Грибов

1С Розница 2.2, сохранить присоединенные к номенклатуре картинки

Присоединенные к номенклатуре файлы можно выгрузить например так:

&НаСервереБезКонтекста
Процедура ПолучитьФайлыНаСервере()
	ном=Справочники.Номенклатура.НайтиПоКоду("1534       ");
	сообщить(ном.ФайлКартинки);
	Запрос = Новый Запрос;
		Запрос.Текст = 		
"ВЫБРАТЬ
|	НоменклатураПрисоединенныеФайлы.Ссылка КАК Ссылка,
|	НоменклатураПрисоединенныеФайлы.ПутьКФайлу КАК ПутьКФайлу,
|	НоменклатураПрисоединенныеФайлы.ТипХраненияФайла КАК ТипХраненияФайла,
|	НоменклатураПрисоединенныеФайлы.Том КАК Том,
|	НоменклатураПрисоединенныеФайлы.ФайлХранилище КАК ФайлХранилище
|ИЗ
|	Справочник.НоменклатураПрисоединенныеФайлы КАК НоменклатураПрисоединенныеФайлы
|ГДЕ
|	НоменклатураПрисоединенныеФайлы.ВладелецФайла.Ссылка = &ном"	;
		
	 Запрос.УстановитьПараметр("ном", ном);					
	 файлы=Запрос.Выполнить().Выбрать();			
	 n=0;
	 Пока файлы.Следующий() Цикл		
		 сообщить(файлы.ПутьКФайлу);
		 сообщить(файлы.ТипХраненияФайла);
		 сообщить(файлы.Том);
		 сообщить(файлы.ФайлХранилище);
		 картинка=ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла(файлы.Ссылка);
		 картинка.Записать("c:\temp\"+n+".jpg");
		 n=n+1;
	 конеццикла;	 
КонецПроцедуры

&НаКлиенте
Процедура ПолучитьФайлыКлиент(Команда)
	ПолучитьФайлыНаСервере();
КонецПроцедуры

Фискализация чеков через онлайн-кассу АТОЛ 55Ф на ОС Ubuntu, python

Прилетела задача фискализировать поступления платежей через оплату услуг с карточек через интернет, из личного кабинета абонента, оплаты абонента посредством Сбербанк-онлайн и т.п. Из ТУ : операционная система семейства Linux.

Было рассмотрено несколько вариантов решения:

1) Сервис Атол-Онлайн. Плюсы: простота интеграции, очень вменяемое API. Минусы — со второго года — выходит очень дорого по сравнению со «своей железкой»

2)PAYONLINE-01-ФА. Плюсы: прям в «базе» нет принтера, что удешевляет. Минусы: нет толкового описания работы с драйверами, примеров, нет драйверов под LInux

3) Атол-55Ф. Плюсы: драйвера под Linux, вменяемое описание работы с примерами на Java, cpp. Плюс натолкнулся на пример работы https://github.com/parshin/kkt с этой железкой. Минусы — дорого по сравнению с 2) но дешево по сравнению с 1)

Собственно драйвера ставятся стандартно. Далее пример пробития чека на python

#!/usr/bin/python2.7
# -*- coding: utf-8 -*-

# import web
import sys
import os
import json
import logging

from conf import *	    # загружаем настройки
import dto9fptr		    # загружаем заголовки драйвера

def DeviceSetup(driver,params):    
    driver.put_DeviceSingleSetting("Port", params["Port"])
    driver.put_DeviceSingleSetting("IPAddress", params["IPAddress"])
    driver.put_DeviceSingleSetting("IPPort", params["IPPort"])
    driver.put_DeviceSingleSetting("Model", params["Model"])
    driver.put_DeviceSingleSetting("Protocol", params["Protocol"])
    driver.put_DeviceSingleSetting("AccessPassword", params["AccessPassword"])
    driver.put_DeviceSingleSetting("UserPassword", params["UserPassword"])
    driver.put_DeviceSingleSetting("Protocol", params["Protocol"])
    driver.put_DeviceSingleSetting('SearchDir', os.path.dirname(DTO_LIB_NAME))
    driver.ApplySingleSettings()
    driver.put_DeviceEnabled(True)
    return 0

def GetCurrentParamDevice(driver):
    result = driver.GetStatus()    
    if result[0]!=0:
	print t_err+unicode(result[1])+t_off
	logging.info(result[1])
	exit(1)
    result = driver.get_DeviceSettings()
    print t_mess+'Текщие настройки: '+t_off + str(result)
    if str(result)=="None":
	etxt="Драйвер не подключился к устройству"
	print t_err+etxt+t_off
	logging.info(etxt)
	exit(1)
    return result

def print_check(driver, check_data):
    res=0
    mess="check_data: " + str(check_data)
    
    print t_mess+mess+t_off
    logging.info(mess)
    
    result = driver.put_DeviceEnabled(True)
    logging.info("put device enabled: " + repr(result).decode("unicode_escape"))
    result_code = driver.get_ResultCode()
    result_description = driver.get_ResultDescription()
    if result_code != 0:
        logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
        logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
	print t_err+str(result_code)+t_off
	print t_err+result_description+t_off
        exit(1)  
    print t_ok+result_description+t_off		
    
    print t_mess+"- переводим ККМ в режим регистрации"+t_off
    result = driver.put_Mode(1)
    logging.info("put mode 1:" + repr(result).decode("unicode_escape"))
    result_code = driver.get_ResultCode()
    result_description = driver.get_ResultDescription()
    if result_code != 0:
        logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
        logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
	print t_err+str(result_code)+t_off
	print t_err+result_description+t_off
    print t_ok+result_description+t_off					   
	
    print t_mess+"- создаем новый документ"+t_off
    result = driver.NewDocument()	
    logging.info("new document:" + repr(result).decode("unicode_escape"))
    result_code = driver.get_ResultCode()
    result_description = driver.get_ResultDescription()
    if result_code == -3822:
        logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
        logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
        logging.error("  trying close shift...")
	print t_err+str(result_code)+t_off
	print t_err+result_description+t_off
	exit(1)
    print t_ok+result_description+t_off	
    
    print t_mess+"- выставляем что тип чека - продажа"+t_off
    result = driver.put_CheckType(1)
    logging.info("put check type:" + repr(result).decode("unicode_escape"))
    result_code = driver.get_ResultCode()
    result_description = driver.get_ResultDescription()
    if result_code != 0:
        logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
        logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
	print t_err+str(result_code)+t_off
	print t_err+result_description+t_off
	exit(1)
    print t_ok+result_description+t_off	
	
    print t_mess+"- открываем чек"+t_off
    result = driver.OpenCheck()
    logging.info("open check:" + repr(result).decode("unicode_escape"))
    result_code = driver.get_ResultCode()
    result_description = driver.get_ResultDescription()
    if result_code != 0:
        logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
        logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
	print t_err+str(result_code)+t_off
	print t_err+result_description+t_off
	exit(1)
    print t_ok+result_description+t_off	
    
    print t_mess+"- регистрация позиций"+t_off
    logging.info("registering positions...")
    
    for position in check_data:
	print "--- №:"+str(position["num"])
	print "--- Дата:"+str(position["docdate"])
	print "--- Всего:"+str(position["summdoc"])
	for goods in position["goods"]:
	    print "---- Товар:"+str(goods["name"])
	    result = driver.put_Name(goods["name"].decode('utf8'))
	    print "---- Цена:"+str(goods["price"])
	    result = driver.put_Price(goods["price"])
	    print "---- Количество:"+str(goods["quiantity"])
	    result = driver.put_Quantity(goods["quiantity"])
	    result = driver.put_TaxNumber(3) 
	    print "---- Сумма:"+str(goods["summ"])
	    result_code = driver.put_PositionSum(goods["summ"]) 
	    print "---- Регистрация позиции:"
	    result_code = driver.Registration() 	    
	    if result_code[0] != 0:
		logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
		logging.error("  result description:" + repr(result_description).decode("unicode_escape"))	    
		print t_err+str(result_code)+t_off
		print t_err+result_description+t_off
		exit(1)
	

	print t_mess+"- прием оплаты"+t_off
	result = driver.put_TypeClose(1)  # Тип оплаты - Платежная карта
	logging.info("put type close:" + repr(result).decode("unicode_escape"))
	result_code = driver.get_ResultCode()
	result_description = driver.get_ResultDescription()
	if result_code != 0:
	    logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
	    logging.error("  result description:" + repr(result_description).decode("unicode_escape"))	    
	    print t_err+str(result_code)+t_off
	    print t_err+result_description+t_off
	    exit(1)

	print t_mess+"- сумма оплаты"+t_off
	result = driver.put_Summ(position["summdoc"])
	logging.info("put summ:" + repr(result).decode("unicode_escape"))
	result_code = driver.get_ResultCode()
	result_description = driver.get_ResultDescription()
	if result_code != 0:
	    logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
	    logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
	    print t_err+str(result_code)+t_off
	    print t_err+result_description+t_off
	    exit(1)

	print t_mess+"- регистрация платежа"+t_off
	result = driver.Payment()
	logging.info("pyment:" + repr(result).decode("unicode_escape"))
	result_code = driver.get_ResultCode()
	result_description = driver.get_ResultDescription()
	if result_code != 0:
	    logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
	    logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
	    print t_err+str(result_code)+t_off
	    print t_err+result_description+t_off
	    exit(1)

	print t_mess+"- проверка фиксации "+t_off
	result = driver.get_ResultCode()
	logging.info("payment result code:" + repr(result).decode("unicode_escape"))
	result_code = driver.get_ResultCode()
	result_description = driver.get_ResultDescription()
	if result_code != 0:
	    logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
	    logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
	    print t_err+str(result_code)+t_off
	    print t_err+result_description+t_off
	    exit(1)

    print t_mess+"- закрытие чека "+t_off
    result = driver.CloseCheck()
    logging.info("close check:" + repr(result).decode("unicode_escape"))
    result_code = driver.get_ResultCode()
    result_description = driver.get_ResultDescription()
    if result_code != 0:
        logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
        logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
        print t_err+str(result_code)+t_off
        print t_err+result_description+t_off
        exit(1)

    print t_mess+"- получение номера чека "+t_off
    result = driver.get_CheckNumber()
    logging.info("check number:" + repr(result).decode("unicode_escape"))
    result_code = driver.get_ResultCode()
    result_description = driver.get_ResultDescription()
    if result_code != 0:
        logging.error("  result code:" + repr(result_code).decode("unicode_escape"))
        logging.error("  result description:" + repr(result_description).decode("unicode_escape"))
        print t_err+str(result_code)+t_off
        print t_err+result_description+t_off
        exit(1)


    exit(1)
    return res

os.environ['LD_LIBRARY_PATH'] = os.path.dirname(os.path.realpath(__file__))
logging.info(os.path.dirname(os.path.realpath(__file__)))
logging.info(os.environ)

print t_mess+"Фискализация чеков v 1.0 (c) 2018 by Pavel Gribov http://грибовы.рф"+t_off

DTO_LIB_NAME = '/opt/ATOL/drivers9/bin/libfptr.so'
VERSION = 15
driver = dto9fptr.Fptr(DTO_LIB_NAME, VERSION)

print t_mess+"Драйвер:"+t_off+str(driver)
print t_mess+"Параметры:"+t_off+str(params)

# устанавливаем параметры соединения
DeviceSetup(driver,params)
# Читаем текущие настройки
cursettings=GetCurrentParamDevice(driver)
# печатаем чек
check_data=[]

goodsa=[]
goodsa.append({"name":"Телематические услуги связи 1","price":0.01,"quiantity":1,"summ":0.01});
goodsa.append({"name":"Телематические услуги связи 2","price":0.01,"quiantity":1,"summ":0.01});

check_data.append({"num":"1","docdate":"07.05.2018","summdoc":0.02,"goods":goodsa});

print check_data
print_check(driver, check_data)

driver.Beep()


#Закончили работу
driver.put_DeviceEnabled(False)
del driver

conf.py:

params = {
    "Port": "TCPIP",
    "IPAddress": "192.168.0.99",
    "IPPort": "5555",
    "Model": "62",
    "AccessPassword": "0",
    "UserPassword": "30",
    "Protocol": "2",
    "LogFileName": "/var/log/kkt.log"
}
t_mess="\x1b[33m"
t_err="\x1b[31m"
t_ok="\x1b[32m"
t_off="\x1b[0m"

Далее осталась рутина, отключить физическую печать, доделать автоматическое открытие-закрытие смены и т.п. Но в принципе всё уже есть в https://github.com/parshin/kkt

В файле conf.py нужно прописать параметры подключения к ККТ IP адрес, порт, путь к лог файлу и т.д. Параметр «Model» смотрим в Руководстве программиста приложение 7 модели ККМ ???(у меня 47 не подошло, подошло 62, почему не понял).

VERSION = 15 — это для драйверов 9.12.1. Возможно потом нужно будет менять на 16 и т.д.

P.S. Решение применимо и для других аппаратов АТОЛ с минимальными изменениями.

Не печатает чек с СН ЕНВД Розница 2.2

Ну хоть ты тресни, но после выставления в настройках организации:

И установка что продажи по складу именно ЕНВД:

На чеке, при фискализации на ККТ всё равно вылезало СН : УСН Доходы. В результате копания кода 1С, в модуле Общиймодуль.ПодключаемоеОборудованиеРК, нашел функцию отвечающую за выдачу на ККТ систему налогообложения:

Функция ПолучитьСистемуНалогообложенияККТ(Организация, ВидНалога, ДатаДокумента = Неопределено) Экспорт
	
	Если НЕ ЗначениеЗаполнено(ДатаДокумента) Тогда
		ДатаДокумента = ТекущаяДатаСеанса();
	КонецЕсли;
	
	Если ВидНалога = Перечисления.ВидыНалогов.ЕНВД Тогда
		Возврат Перечисления.ТипыСистемНалогообложенияККТ.ЕНВД;
	ИначеЕсли ВидНалога = Перечисления.ВидыНалогов.ЕСХН Тогда
		Возврат Перечисления.ТипыСистемНалогообложенияККТ.ЕСН;
	ИначеЕсли ВидНалога = Перечисления.ВидыНалогов.ПСН Тогда
		Возврат Перечисления.ТипыСистемНалогообложенияККТ.Патент;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	СистемыНалогообложенияОрганизацийСрезПоследних.СистемаНалогообложения,
	|	СистемыНалогообложенияОрганизацийСрезПоследних.ОбъектНалогообложения
	|ИЗ
	|	РегистрСведений.СистемыНалогообложенияОрганизаций.СрезПоследних(&ДатаДокумента, Организация = &Организация) КАК СистемыНалогообложенияОрганизацийСрезПоследних";
	
	Запрос.УстановитьПараметр("ДатаДокумента", ДатаДокумента);
	Запрос.УстановитьПараметр("Организация"  , Организация);
	Результат = Запрос.Выполнить();
	Выборка = Результат.Выбрать();	
	Если Выборка.Следующий() Тогда		
		Если Выборка.СистемаНалогообложения = Перечисления.СистемыНалогообложения.Общая Тогда			
			Возврат Перечисления.ТипыСистемНалогообложенияККТ.ОСН;
		ИначеЕсли Выборка.ОбъектНалогообложения = Перечисления.ОбъектыНалогообложенияПоУСН.Доходы Тогда
			Возврат Перечисления.ТипыСистемНалогообложенияККТ.УСНДоход;
		Иначе			
			Возврат Перечисления.ТипыСистемНалогообложенияККТ.УСНДоходРасход
		КонецЕсли;
	Иначе
		Возврат Перечисления.ТипыСистемНалогообложенияККТ.ОСН;
	КонецЕсли;
	
	
КонецФункции

И что мы тут видим? Определение СН идет по выборке из регистра РегистрСведений.СистемыНалогообложенияОрганизаций. Четко видим что ЕНВД присутствует. Идём в форму заполнения этого регистра и видим:

Что за хрень ерунда? Видишь суслика? Нет. А он есть. 1С ники писали-писали, но что-то не дописали. Теоретически по моему предположению, в функции выше должна быть проверка не только СН у организации, но и по складу. Но они её засунули в другую обработку — при сборке позиций товара. И там эта «ЕНВД» в чеке уже никак не участвует. Точнее участвет, но не понятно как. Есть вероятность, что я конечно какую-то галочку очередную не нашел. А может и ошибка 1С. Может в следующих релизах поправят. А пока добавил «костыль»:

Если Выборка.Следующий() Тогда
		// грибов. Костыль чтоб печатался чек ЕНВД
		Если Выборка.СистемаНалогообложения = Перечисления.СистемыНалогообложения.Общая Тогда
			Возврат Перечисления.ТипыСистемНалогообложенияККТ.ЕНВД;
			//Возврат Перечисления.ТипыСистемНалогообложенияККТ.ОСН;
		ИначеЕсли Выборка.ОбъектНалогообложения = Перечисления.ОбъектыНалогообложенияПоУСН.Доходы Тогда
			Возврат Перечисления.ТипыСистемНалогообложенияККТ.ЕНВД;
			//Возврат Перечисления.ТипыСистемНалогообложенияККТ.УСНДоход;
		Иначе
			Возврат Перечисления.ТипыСистемНалогообложенияККТ.ЕНВД;
			//Возврат Перечисления.ТипыСистемНалогообложенияККТ.УСНДоходРасход
		КонецЕсли;
	Иначе
		Возврат Перечисления.ТипыСистемНалогообложенияККТ.ЕНВД;
		//Возврат Перечисления.ТипыСистемНалогообложенияККТ.ОСН;
	КонецЕсли;

 

Программный вызов отчета СКД с параметрами и отборами. Выгрузка в файл

Можно сделать примерно так:

таб1=новый ТабличныйДокумент();	   
	СКД=Отчеты.ОценкаВаловойПрибыли.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
	
	Настройки=СКД.НастройкиПоУмолчанию;	
	ПераметрыСКД=Настройки.ПараметрыДанных.Элементы;	
	прскд=ПераметрыСКД.Найти("Период");	
		пер=Новый СтандартныйПериод;
		пер.ДатаНачала=НачалоМесяца(ТекущаяДата());
		пер.ДатаОкончания=КонецДня(ТекущаяДата());
	прскд=пер;
			ЭлементОтбора=Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
				ЭлементОтбора.ВидСравнения=ВидСравненияКомпоновкиДанных.Равно;
				ЭлементОтбора.ЛевоеЗначение=Новый ПолеКомпоновкиДанных("Магазин");//поле отбора
				ЭлементОтбора.ПравоеЗначение=Справочники.Магазины.НайтиПоНаименованию("Вологда Торговля");
				ЭлементОтбора.Использование=Истина;
				ЭлементОтбора.ИдентификаторПользовательскойНастройки=Новый УникальныйИдентификатор();//добавляет отбор  в состав пользовательских настроек
	
	
	 	Расшифровка = Новый ДанныеРасшифровкиКомпоновкиДанных;
		КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;    
		
	    //Передаем в макет компоновки схему, настройки и данные расшифровки
	    МакетКомпоновки = КомпоновщикМакета.Выполнить(СКД, Настройки, Расшифровка);    
	    ВнешниеПараметры = Новый Структура;    		
		
	    //Выполним компоновку с помощью процессора компоновки
	    ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
	    ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеПараметры, Расшифровка);    
		
	    //Выводим результат в табличный документ
	    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
	    ПроцессорВывода.УстановитьДокумент(таб1);    
	    ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных, Истина);    	 
		
		таб1.Записать("c:\temp\выловая_прибыль.xls",ТипФайлаТабличногоДокумента.XLS);