Включает перемещение по ячейкам, стикеровку МП, синхронизацию справочников и обработку кодов маркировки. Co-authored-by: Cursor <cursoragent@cursor.com>
1431 lines
108 KiB
Plaintext
1431 lines
108 KiB
Plaintext
|
||
#Область ПрограммныйИнтерфейс
|
||
|
||
// Выполняет проверку правильности заполнения тегов в соответствии с ФФД
|
||
//
|
||
// Параметры:
|
||
// ДанныеЧека - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// ИдентификаторУстройства - СправочникСсылка.ПодключаемоеОборудование - Не обязательный
|
||
// Ошибки - Массив из строка - Строки ошибок по результатам контроля
|
||
// ИсправленыОсновныеПараметры - Булево
|
||
//
|
||
// Возвращаемое значение:
|
||
// Булево.
|
||
Функция ВыполненаПроверкаОбязательностиИПравильностиЗаполненияТэгов(ДанныеЧека, ИдентификаторУстройства, Ошибки = Неопределено, ИсправленыОсновныеПараметры = Неопределено) Экспорт
|
||
|
||
Результат = Ложь;
|
||
Проверка = ПараметрыПроверки();
|
||
Если Не ЗначениеЗаполнено(ИдентификаторУстройства) Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Не выбрано устройство'"));
|
||
Ошибки = Проверка.Ошибки;
|
||
Возврат Результат;
|
||
КонецЕсли;
|
||
|
||
ПараметрыРегистрации = ОборудованиеЧекопечатающиеУстройства.ПараметрыРегистрацииУстройства(ИдентификаторУстройства);
|
||
ПривестиАдресИМестоРасчетов(ДанныеЧека, ПараметрыРегистрации);
|
||
ПривестиДанныеКТребуемомуФормату(ДанныеЧека, ИсправленыОсновныеПараметры, ПараметрыРегистрации);
|
||
|
||
СтруктураДанныхФЛК = СтруктураДанныхФорматноЛогическогоКонтроля(ИдентификаторУстройства);
|
||
Проверка.ВерсияФФД = СтруктураДанныхФЛК.ФорматФД;
|
||
ДанныеЧека.Вставить("ФорматФД", СтруктураДанныхФЛК.ФорматФД);
|
||
ЗаполнитьЗначенияСвойств(Проверка,
|
||
ОбщегоНазначенияБПО.ЗначенияРеквизитовОбъекта(ИдентификаторУстройства, "ИспользуетсяФН36, ТипОборудования"));
|
||
|
||
ПроверитьРеквизит(Проверка, ДанныеЧека, "АдресРасчетов");
|
||
ПроверитьРеквизит(Проверка, ДанныеЧека, "МестоРасчетов", "1.05, 1.1, 1.2");
|
||
ПроверитьРеквизит(Проверка, ДанныеЧека, "ОрганизацияНазвание");
|
||
ПроверитьРеквизит(Проверка, ДанныеЧека, "ОрганизацияИНН");
|
||
ПроверитьРеквизит(Проверка, ДанныеЧека, "ТипРасчета");
|
||
ПроверитьРеквизит(Проверка, ДанныеЧека, "СистемаНалогообложения");
|
||
ПроверитьРеквизит(Проверка, ДанныеЧека, "Кассир");
|
||
ПроверитьДлинуРеквизита(Проверка, ДанныеЧека, "Кассир", 64);
|
||
ПроверитьРеквизитИНН (Проверка, ДанныеЧека, "КассирИНН");
|
||
ПроверитьСведенияОПокупателе(Проверка, ДанныеЧека);
|
||
ПроверитьКодыНалогообложения(Проверка, ДанныеЧека, ПараметрыРегистрации.КодыСистемыНалогообложения);
|
||
ПроверитьЭлектронныйЧек(Проверка, ДанныеЧека);
|
||
|
||
СуммыПозиций = ПараметрыСуммыПозиций();
|
||
СуммыОплат = ПараметрыСуммыОплат();
|
||
ВыполнитьПроверкуФактическойОплаты = Ложь;
|
||
Для Каждого Позиция Из ДанныеЧека.ПозицииЧека Цикл
|
||
УвеличитьНомерПозиции(Проверка);
|
||
Если Позиция.Свойство("ФискальнаяСтрока") Тогда
|
||
ПроверитьРеквизит(Проверка, Позиция, "Количество");
|
||
ПроверитьРеквизит(Проверка, Позиция, "ПризнакСпособаРасчета", "1.05, 1.1, 1.2");
|
||
ПроверитьРеквизит(Проверка, Позиция, "ПризнакПредметаРасчета", "1.1, 1.2");
|
||
ПроверитьДанныеАгента(Проверка, ДанныеЧека, Позиция);
|
||
ПроверитьДанныеПоставщика(Проверка, ДанныеЧека, Позиция);
|
||
ВычислитьСуммыПозиций(СуммыПозиций, Позиция);
|
||
ПреобразоватьПризнакПредметаРасчета(Проверка, Позиция);
|
||
ПризнакСпособаРасчета = Позиция.ПризнакСпособаРасчета;
|
||
Если ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаЧастичная
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ОплатаКредита Тогда
|
||
ВыполнитьПроверкуФактическойОплаты = Истина;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
Для Каждого ЭлементОплаты Из ДанныеЧека.ТаблицаОплат Цикл
|
||
ПроверитьРеквизит(Проверка, ЭлементОплаты, "ТипОплаты");
|
||
ВычислитьСуммыОплат(СуммыОплат, ЭлементОплаты);
|
||
КонецЦикла;
|
||
ВычислитьСуммуНаличныеБезСдачи(СуммыПозиций, СуммыОплат);
|
||
ПроверитьСуммыОплат(Проверка, СуммыПозиций, СуммыОплат);
|
||
Если ВыполнитьПроверкуФактическойОплаты Тогда
|
||
ПроверитьСуммуФактическихОплат(Проверка, СуммыПозиций, СуммыОплат);
|
||
КонецЕсли;
|
||
ПреобразоватьСистемуНалогообложения(Проверка, ДанныеЧека);
|
||
|
||
Результат = Проверка.Ошибки.Количество() = 0;
|
||
Ошибки = СтрСоединить(Проверка.Ошибки, Символы.ПС);
|
||
|
||
Возврат Результат;
|
||
|
||
КонецФункции
|
||
|
||
// Выполняет корректировку данных чека
|
||
//
|
||
// Параметры:
|
||
// ДанныеЧека - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// ИсправленыОсновныеПараметры - Булево
|
||
//
|
||
Процедура ПривестиДанныеКТребуемомуФормату(ДанныеЧека, ИсправленыОсновныеПараметры = Неопределено, ПараметрыРегистрации = Неопределено) Экспорт
|
||
|
||
Если ДанныеЧека.ИндивидуальныйРежимПодготовкиДанныхКПередачеВОФД Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
Если ДанныеЧека.СпособФорматноЛогическогоКонтроля = Перечисления.СпособыФорматноЛогическогоКонтроля.НеКонтролировать Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
СуммыПозиций = ПараметрыСуммыПозиций();
|
||
НужноПривестиСуммы = Ложь;
|
||
ИсправленыОсновныеПараметры = Ложь;
|
||
Для Каждого Позиция Из ДанныеЧека.ПозицииЧека Цикл
|
||
Если Позиция.Свойство("ФискальнаяСтрока") Тогда
|
||
|
||
ПривестиЕслиСпособРасчетаБезПередачиТовара(Позиция, ИсправленыОсновныеПараметры);
|
||
ПривестиСтавкиНДС(Позиция);
|
||
ВычислитьСуммыПозиций(СуммыПозиций, Позиция);
|
||
|
||
ПризнакСпособаРасчета = Позиция.ПризнакСпособаРасчета;
|
||
Если ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаЧастичная
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ОплатаКредита Тогда
|
||
НужноПривестиСуммы = Истина;
|
||
КонецЕсли;
|
||
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
Если НужноПривестиСуммы Тогда
|
||
СуммыОплат = ПараметрыСуммыОплат();
|
||
Для Каждого СтрокаОплат Из ДанныеЧека.ТаблицаОплат Цикл
|
||
ВычислитьСуммыОплат(СуммыОплат, СтрокаОплат);
|
||
КонецЦикла;
|
||
ВычислитьСуммуНаличныеБезСдачи(СуммыПозиций, СуммыОплат);
|
||
ПривестиСуммыПозицийЧекаКСуммеТаблицыОплат(ДанныеЧека, СуммыПозиций, СуммыОплат);
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
// Определяет требуется ли выполнить корректировку сумм в позициях чека
|
||
//
|
||
// Параметры:
|
||
// ДанныеЧека - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// ИдентификаторУстройства - СправочникСсылка.ПодключаемоеОборудование - Не обязательный
|
||
// Если заполнено оборудование и не заполнен способ контроля в общих параметрах,
|
||
// то способ контроля и допустимое расхождение получаются из подключаемого оборудования.
|
||
//
|
||
// Возвращаемое значение:
|
||
// Булево
|
||
//
|
||
Функция НуженФорматноЛогическийКонтроль(ДанныеЧека, ИдентификаторУстройства = Неопределено) Экспорт
|
||
|
||
СтандартнаяОбработка = Истина;
|
||
ПереопределяемыйРезультат = ФорматноЛогическийКонтрольПереопределяемый.НуженФорматноЛогическийКонтроль(ДанныеЧека, СтандартнаяОбработка);
|
||
Если Не СтандартнаяОбработка Тогда
|
||
Возврат ПереопределяемыйРезультат;
|
||
КонецЕсли;
|
||
|
||
СпособФорматноЛогическогоКонтроля = ДанныеЧека.СпособФорматноЛогическогоКонтроля;
|
||
ДопустимоеРасхождение = ДанныеЧека.ДопустимоеРасхождениеФорматноЛогическогоКонтроля;
|
||
|
||
Если СпособФорматноЛогическогоКонтроля = Неопределено И ИдентификаторУстройства <> Неопределено Тогда
|
||
СтруктураДанныхФЛК = СтруктураДанныхФорматноЛогическогоКонтроля(ИдентификаторУстройства);
|
||
ДопустимоеРасхождение = СтруктураДанныхФЛК.ДопустимоеРасхождениеФорматноЛогическогоКонтроля;
|
||
СпособФорматноЛогическогоКонтроля = СтруктураДанныхФЛК.СпособФорматноЛогическогоКонтроля;
|
||
КонецЕсли;
|
||
|
||
Если НЕ ЗначениеЗаполнено(СпособФорматноЛогическогоКонтроля)
|
||
ИЛИ СпособФорматноЛогическогоКонтроля = Перечисления.СпособыФорматноЛогическогоКонтроля.НеКонтролировать Тогда
|
||
Возврат Ложь;
|
||
КонецЕсли;
|
||
|
||
Для Каждого ТекущаяПозиция Из ДанныеЧека.ПозицииЧека Цикл
|
||
Если Не ТекущаяПозиция.Свойство("ФискальнаяСтрока") Тогда
|
||
Продолжить;
|
||
КонецЕсли;
|
||
|
||
Количество = ?(ТекущаяПозиция.Количество = 0, 1, ТекущаяПозиция.Количество);
|
||
Если Количество = 1 Тогда
|
||
Если ТекущаяПозиция.ЦенаСоСкидками <> ТекущаяПозиция.Сумма Тогда
|
||
Возврат Истина;
|
||
КонецЕсли;
|
||
Иначе
|
||
Если Окр(ТекущаяПозиция.ЦенаСоСкидками * Количество, 2, 1) <> ТекущаяПозиция.Сумма Тогда
|
||
Сумма = ТекущаяПозиция.Сумма;
|
||
// Умножаем входящее количество на заданную цену и получаем новую промежуточную сумму.
|
||
// Сумму НЕ округляем - Требования АСК ККТ ФНС РФ.
|
||
НоваяСуммаБезОкругления = Количество * ТекущаяПозиция.ЦенаСоСкидками;
|
||
// Вычисляем разницу между промежуточной и входящей суммой.
|
||
РазницаСумм = НоваяСуммаБезОкругления - Сумма;
|
||
// Если разница допустима - оставляем одну строку.
|
||
// Если разницы нет - оставляем одну строку.
|
||
Если РазницаСумм >= -ДопустимоеРасхождение И РазницаСумм <= ДопустимоеРасхождение Тогда
|
||
// Дополнительно получаем расчетную цену с учетом скидок делением входящей суммы на входящее количество.
|
||
// Цену округляем.
|
||
РасчетнаяЦена = Окр(Сумма / Количество, 2, 1);
|
||
Если ТекущаяПозиция.ЦенаСоСкидками <> РасчетнаяЦена Тогда
|
||
// Но. Если цена не совпадает с расчетной - все равно надо ее пересчитывать.
|
||
Возврат Истина;
|
||
КонецЕсли;
|
||
Иначе
|
||
// Надо разделять строку.
|
||
Возврат Истина;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
Возврат Ложь;
|
||
|
||
КонецФункции
|
||
|
||
// Выполняет проверку сумм фискальных строк, осуществляя форматно-логический контроль чека.
|
||
// Функция переопределяется методом ФорматноЛогическийКонтрольПереопределяемый.ПровестиФорматноЛогическийКонтроль.
|
||
//
|
||
// Параметры:
|
||
// ДанныеЧека - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// ИдентификаторУстройства - СправочникСсылка.ПодключаемоеОборудование - Не обязательный
|
||
// Если заполнено оборудование и не заполнен способ контроля в общих параметрах,
|
||
// то способ контроля и допустимое расхождение получаются из подключаемого оборудования.
|
||
//
|
||
Процедура ПровестиФорматноЛогическийКонтроль(ДанныеЧека, ИдентификаторУстройства = Неопределено) Экспорт
|
||
|
||
СтандартнаяОбработка = Истина;
|
||
ФорматноЛогическийКонтрольПереопределяемый.ПровестиФорматноЛогическийКонтроль(ДанныеЧека, СтандартнаяОбработка, ИдентификаторУстройства);
|
||
Если Не СтандартнаяОбработка Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
Если Не НуженФорматноЛогическийКонтроль(ДанныеЧека, ИдентификаторУстройства) Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
СпособФорматноЛогическогоКонтроля = ДанныеЧека.СпособФорматноЛогическогоКонтроля;
|
||
ДопустимоеРасхождение = ДанныеЧека.ДопустимоеРасхождениеФорматноЛогическогоКонтроля;
|
||
|
||
Если СпособФорматноЛогическогоКонтроля = Неопределено И ИдентификаторУстройства <> Неопределено Тогда
|
||
СтруктураДанныхФЛК = СтруктураДанныхФорматноЛогическогоКонтроля(ИдентификаторУстройства);
|
||
ДопустимоеРасхождение = СтруктураДанныхФЛК.ДопустимоеРасхождениеФорматноЛогическогоКонтроля;
|
||
СпособФорматноЛогическогоКонтроля = СтруктураДанныхФЛК.СпособФорматноЛогическогоКонтроля;
|
||
КонецЕсли;
|
||
|
||
Если ЗначениеЗаполнено(СпособФорматноЛогическогоКонтроля) Тогда
|
||
НовыеПозицииЧека = Новый Массив;
|
||
Если СпособФорматноЛогическогоКонтроля = Перечисления.СпособыФорматноЛогическогоКонтроля.НеКонтролировать Тогда
|
||
Возврат;
|
||
ИначеЕсли СпособФорматноЛогическогоКонтроля = Перечисления.СпособыФорматноЛогическогоКонтроля.ЗачитыватьСуммы Тогда
|
||
ПривестиПозицииЧекаПоАлгоритмуЗачитыватьСуммы(ДанныеЧека.ПозицииЧека, НовыеПозицииЧека, ДопустимоеРасхождение);
|
||
ДанныеЧека.ПозицииЧека = НовыеПозицииЧека;
|
||
ИначеЕсли СпособФорматноЛогическогоКонтроля = Перечисления.СпособыФорматноЛогическогоКонтроля.РазделятьСтроки Тогда
|
||
ПривестиПозицииЧекаПоАлгоритмуРазделятьСтроки(ДанныеЧека.ПозицииЧека, НовыеПозицииЧека, ДопустимоеРасхождение);
|
||
ДанныеЧека.ПозицииЧека = НовыеПозицииЧека;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
// Структура данных форматно-логического контроля
|
||
//
|
||
// Параметры:
|
||
// ПодключаемоеОборудование - СправочникСсылка.ПодключаемоеОборудование - Устройство, фискализирующее чек
|
||
//
|
||
// Возвращаемое значение:
|
||
// Структура - Структура данных форматно логического контроля:
|
||
// * СпособФорматноЛогическогоКонтроля - Неопределено
|
||
// - ПеречислениеСсылка.СпособыФорматноЛогическогоКонтроля
|
||
// * ДопустимоеРасхождениеФорматноЛогическогоКонтроля - Число -
|
||
// * ФорматФД - Строка -
|
||
//
|
||
Функция СтруктураДанныхФорматноЛогическогоКонтроля(ПодключаемоеОборудование) Экспорт
|
||
|
||
ФорматФД = "1.0";
|
||
|
||
ВозвращаемаяСтруктура = Новый Структура;
|
||
ВозвращаемаяСтруктура.Вставить("СпособФорматноЛогическогоКонтроля" , Неопределено);
|
||
ВозвращаемаяСтруктура.Вставить("ДопустимоеРасхождениеФорматноЛогическогоКонтроля", 0.01);
|
||
ВозвращаемаяСтруктура.Вставить("ФорматФД", ФорматФД);
|
||
|
||
СтандартнаяОбработка = Истина;
|
||
ФорматноЛогическийКонтрольПереопределяемый.ПолучитьСтруктуруДанныхФорматноЛогическогоКонтроля(ПодключаемоеОборудование, ВозвращаемаяСтруктура, СтандартнаяОбработка);
|
||
|
||
Если Не СтандартнаяОбработка Тогда
|
||
Возврат ВозвращаемаяСтруктура;
|
||
КонецЕсли;
|
||
|
||
Запрос = Новый Запрос;
|
||
Запрос.Текст =
|
||
"ВЫБРАТЬ
|
||
| ПодключаемоеОборудование.ДопустимоеРасхождениеФорматноЛогическогоКонтроля КАК ДопустимоеРасхождениеФорматноЛогическогоКонтроля,
|
||
| ПодключаемоеОборудование.СпособФорматноЛогическогоКонтроля КАК СпособФорматноЛогическогоКонтроля,
|
||
| ПодключаемоеОборудованиеПараметрыРегистрации.ЗначениеПараметра КАК ФорматФД
|
||
|ИЗ
|
||
| Справочник.ПодключаемоеОборудование КАК ПодключаемоеОборудование
|
||
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПодключаемоеОборудование.ПараметрыРегистрации КАК ПодключаемоеОборудованиеПараметрыРегистрации
|
||
| ПО ПодключаемоеОборудование.Ссылка = ПодключаемоеОборудованиеПараметрыРегистрации.Ссылка
|
||
| И (ПодключаемоеОборудованиеПараметрыРегистрации.Ссылка = &Ссылка)
|
||
| И (ПодключаемоеОборудованиеПараметрыРегистрации.НаименованиеПараметра = ""ВерсияФФДККТ"")
|
||
|ГДЕ
|
||
| ПодключаемоеОборудование.Ссылка = &Ссылка";
|
||
|
||
Запрос.УстановитьПараметр("Ссылка", ПодключаемоеОборудование);
|
||
|
||
Результат = Запрос.Выполнить();
|
||
Если Не Результат.Пустой() Тогда
|
||
Выборка = Результат.Выбрать();
|
||
Выборка.Следующий();
|
||
ВозвращаемаяСтруктура.ФорматФД = Выборка.ФорматФД;
|
||
ВозвращаемаяСтруктура.СпособФорматноЛогическогоКонтроля = Выборка.СпособФорматноЛогическогоКонтроля;
|
||
ВозвращаемаяСтруктура.ДопустимоеРасхождениеФорматноЛогическогоКонтроля = Выборка.ДопустимоеРасхождениеФорматноЛогическогоКонтроля;
|
||
КонецЕсли;
|
||
|
||
Возврат ВозвращаемаяСтруктура;
|
||
|
||
КонецФункции
|
||
|
||
#КонецОбласти
|
||
|
||
#Область СлужебныеПроцедурыИФункции
|
||
|
||
// Возвращает структуру проверки форматно-логического контроля
|
||
//
|
||
// Возвращаемое значение:
|
||
// Структура:
|
||
// * ВерсияФФД - Строка - Версия формата, по которому выполнять проверку
|
||
// * ТипОборудования - ПеречислениеСсылка.ТипыПодключаемогоОборудования
|
||
// * ИспользуетсяФН36 - Булево -
|
||
// * Ошибки - Массив из Строка - строки содержащие описание найденных ошибок
|
||
// * НомерПозиции - Число - номер проверяемой позиции в чеке
|
||
//
|
||
Функция ПараметрыПроверки()
|
||
Параметры = Новый Структура;
|
||
Параметры.Вставить("ВерсияФФД", "1.2");
|
||
Параметры.Вставить("ТипОборудования", Перечисления.ТипыПодключаемогоОборудования.ПустаяСсылка());
|
||
Параметры.Вставить("ИспользуетсяФН36", Ложь);
|
||
Параметры.Вставить("Ошибки", Новый Массив); // Массив из Строка
|
||
Параметры.Вставить("НомерПозиции",0);
|
||
Возврат Параметры;
|
||
КонецФункции
|
||
|
||
// Скопировать структуру.
|
||
//
|
||
// Параметры:
|
||
// Данные - Произвольный, Структура - Текущая позиция
|
||
//
|
||
// Возвращаемое значение:
|
||
// Структура
|
||
//
|
||
Функция СкопироватьСтруктуру(Данные)
|
||
|
||
НоваяСтруктура = Новый Структура;
|
||
Для Каждого ЭлементСтруктуры Из Данные Цикл
|
||
НоваяСтруктура.Вставить(ЭлементСтруктуры.Ключ, ЭлементСтруктуры.Значение);
|
||
КонецЦикла;
|
||
|
||
Возврат НоваяСтруктура;
|
||
|
||
КонецФункции
|
||
|
||
// Функция сортирует массив фискальных строк
|
||
//
|
||
// Параметры:
|
||
// МассивФискальныхСтрок - Массив из см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// ИмяРеквизита - Строка
|
||
Процедура СортироватьМассивФискальныхСтрок(МассивФискальныхСтрок, ИмяРеквизита = "СтрокаПоследнегоТовара")
|
||
|
||
МаксимальныйИндекс = МассивФискальныхСтрок.ВГраница();
|
||
Если МаксимальныйИндекс >= 0 Тогда
|
||
// Начинаем со второго элемента.
|
||
Для ТекущийИндекс = 1 По МаксимальныйИндекс Цикл
|
||
ТекущаяСтрока = МассивФискальныхСтрок[ТекущийИндекс];
|
||
НоваяТекущаяСтрока = СкопироватьСтруктуру(ТекущаяСтрока);
|
||
НовыйИндексТекущейСтроки = -1;
|
||
Для ОбратныйСчетчик = 1 По ТекущийИндекс Цикл
|
||
ПредыдущаяСтрока = МассивФискальныхСтрок[ТекущийИндекс - ОбратныйСчетчик];
|
||
Если ПредыдущаяСтрока[ИмяРеквизита] > ТекущаяСтрока[ИмяРеквизита] Тогда
|
||
НоваяПредыдущаяСтрока = СкопироватьСтруктуру(ПредыдущаяСтрока);
|
||
|
||
НовыйИндексТекущейСтроки = ТекущийИндекс - ОбратныйСчетчик;
|
||
МассивФискальныхСтрок.Удалить(НовыйИндексТекущейСтроки + 1);
|
||
МассивФискальныхСтрок.Вставить(НовыйИндексТекущейСтроки + 1, НоваяПредыдущаяСтрока);
|
||
Иначе
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
Если НовыйИндексТекущейСтроки >=0 Тогда
|
||
МассивФискальныхСтрок.Удалить(НовыйИндексТекущейСтроки);
|
||
МассивФискальныхСтрок.Вставить(НовыйИндексТекущейСтроки, НоваяТекущаяСтрока);
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
#Область СпециальныеПроверки
|
||
|
||
// Выполняет проверку кода налогообложения в данных чека
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки.
|
||
// Данные - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// ДоступныеКодыСистемыНалогообложения - Строка
|
||
//
|
||
Процедура ПроверитьКодыНалогообложения(Проверка, Данные, ДоступныеКодыСистемыНалогообложения)
|
||
|
||
Если Проверка.ТипОборудования = Перечисления.ТипыПодключаемогоОборудования.ККТ Тогда
|
||
// Проверка системы налогообложения
|
||
КодыНалогообложения = СтрРазделить(ДоступныеКодыСистемыНалогообложения, ",");
|
||
СистемаНалогообложения = ОборудованиеЧекопечатающиеУстройстваКлиентСервер.КодСистемыНалогообложенияККТ(Данные.СистемаНалогообложения);
|
||
Если КодыНалогообложения.Найти(Строка(СистемаНалогообложения)) = Неопределено Тогда
|
||
ТекстОшибки = НСтр("ru = 'ККТ не зарегистрирована с указанной системой налогообложения: ""%1""'");
|
||
ТекстОшибки = СтрШаблон(ТекстОшибки, Строка(Данные.СистемаНалогообложения));
|
||
Проверка.Ошибки.Добавить(ТекстОшибки);
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
// Выполняет проверку реквизитов для электронного чека
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки.
|
||
// Данные - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
//
|
||
Процедура ПроверитьЭлектронныйЧек(Проверка, Данные)
|
||
|
||
// Электронный чек
|
||
Если Данные.Электронно
|
||
И ПустаяСтрока(Данные.ПокупательEmail) И ПустаяСтрока(Данные.ПокупательНомер) Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Для электронного чека нужно указать либо Email, либо телефон.'"));
|
||
КонецЕсли;
|
||
|
||
Если Данные.Отправляет1СEmail И ПустаяСтрока(Данные.ПокупательEmail) Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Не заполнен E-mail'"));
|
||
КонецЕсли;
|
||
|
||
Если Данные.Отправляет1СSMS И НЕ ЗначениеЗаполнено(Данные.ПокупательНомер) Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Не заполнен номер телефона'"));
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
// Выполняет проверку сведений о покупателе в данных чека
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки.
|
||
// Данные - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
//
|
||
Процедура ПроверитьСведенияОПокупателе(Проверка, Данные)
|
||
|
||
// при формате 1.05 реквизит необязателен
|
||
Если ВерсияФФД(Проверка, "1.05") Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
СведенияОПокупателе = Данные.СведенияОПокупателе;
|
||
Если ПустаяСтрока(Данные.Получатель) И ПустаяСтрока(СведенияОПокупателе.Покупатель) Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
Если ЗначениеЗаполнено(Данные.ПолучательИНН) Или ЗначениеЗаполнено(СведенияОПокупателе.ПокупательИНН) Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
Если Данные.ЕстьПерсональныеДанные Тогда
|
||
ПерсональныеДанные = ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыПерсональныеДанныеПокупателя();
|
||
ТипПерсональныхДанных = Данные.ТипПерсональныхДанных;
|
||
|
||
МенеджерОборудованияВызовСервераПереопределяемый.ОбработкаЗаполненияПерсональныхДанных(
|
||
ПерсональныеДанные,
|
||
Данные.СубъектПерсональныхДанных,
|
||
ТипПерсональныхДанных,
|
||
?(ПустаяСтрока(Данные.ДатаВремя), ОбщегоНазначенияБПО.ДатаСеанса(), Данные.ДатаВремя));
|
||
|
||
Если ТипПерсональныхДанных = Перечисления.ТипыПерсональныхДанныхККТ.ИНН И ЗначениеЗаполнено(ПерсональныеДанные.ИНН) Тогда
|
||
Возврат;
|
||
ИначеЕсли ТипПерсональныхДанных = Перечисления.ТипыПерсональныхДанныхККТ.ПаспортныеДанные
|
||
И ЗначениеЗаполнено(ПерсональныеДанные.ДатаРождения)
|
||
И ЗначениеЗаполнено(ПерсональныеДанные.ВидДокумента)
|
||
И ЗначениеЗаполнено(ПерсональныеДанные.ДанныеДокумента) Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Не указан ИНН или дата рождения и реквизиты документа удостоверяющего личность покупателя.'"));
|
||
|
||
КонецПроцедуры
|
||
|
||
// Выполняет проверку заполнения данных агента
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки.
|
||
// ДанныеЧека - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// Позиция - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыФискальнойСтрокиЧека
|
||
//
|
||
Процедура ПроверитьДанныеАгента(Проверка, ДанныеЧека, Позиция)
|
||
|
||
Если ЗаполненРеквизит(Проверка, Позиция, "ПризнакАгентаПоПредметуРасчета") Тогда
|
||
|
||
ПризнакАгента = Неопределено;
|
||
ПризнакАгентаПоПредметуРасчета = Неопределено;
|
||
Если ЕстьРеквизит(Проверка, ДанныеЧека, "ПризнакАгента", ПризнакАгента)
|
||
И ЗначениеЗаполнено(ПризнакАгента)
|
||
И ЕстьРеквизит(Проверка, Позиция, "ПризнакАгентаПоПредметуРасчета", ПризнакАгентаПоПредметуРасчета)
|
||
И ЗначениеЗаполнено(ПризнакАгентаПоПредметуРасчета) Тогда
|
||
Если ДанныеЧека.ПризнакАгента <> Позиция.ПризнакАгентаПоПредметуРасчета Тогда
|
||
ШаблонОшибки = НСтр("ru = 'Признак платежного агента в шапке не совпадает с признаком платежного агента по предмету расчета в строке №%2.'");
|
||
Проверка.Ошибки.Добавить(ТекстОшибки(ШаблонОшибки, "", Проверка.НомерПозиции));
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
МассивДанных = Новый Массив();
|
||
МассивДанных.Добавить(ДанныеЧека.ДанныеАгента.ОператорПеревода);
|
||
МассивДанных.Добавить(Позиция.ДанныеАгента.ОператорПеревода);
|
||
|
||
ПризнакАгентаПоПредметуРасчета = Позиция.ПризнакАгентаПоПредметуРасчета;
|
||
Если ПризнакАгентаПоПредметуРасчета = Перечисления.ПризнакиАгента.БанковскийПлатежныйАгент
|
||
Или ПризнакАгентаПоПредметуРасчета = Перечисления.ПризнакиАгента.БанковскийПлатежныйСубагент Тогда
|
||
ШаблонОшибки = НСтр("ru = 'Не установлен %1 оператора перевода банковского платежного агента.'");
|
||
ПроверитьРеквизитВМассивеДанных(Проверка, МассивДанных, "Телефон",, ШаблонОшибки);
|
||
ПроверитьРеквизитВМассивеДанных(Проверка, МассивДанных, "Адрес",, ШаблонОшибки);
|
||
ПроверитьРеквизитВМассивеДанных(Проверка, МассивДанных, "ИНН",, ШаблонОшибки);
|
||
ШаблонОшибки = НСтр("ru = 'Не установлено %1 оператора перевода банковского платежного агента.'");
|
||
ПроверитьРеквизитВМассивеДанных(Проверка, МассивДанных, "Наименование",, ШаблонОшибки);
|
||
КонецЕсли;
|
||
|
||
ШаблонОшибки = НСтр("ru = '%1 оператора перевода в строке %2 не равен этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Телефон", ШаблонОшибки);
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Адрес", ШаблонОшибки);
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "ИНН", ШаблонОшибки);
|
||
ШаблонОшибки = НСтр("ru = '%1 оператора перевода в строке %2 не равно этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Наименование", ШаблонОшибки);
|
||
|
||
МассивДанных.Очистить();
|
||
МассивДанных.Добавить(ДанныеЧека.ДанныеАгента.ОператорПоПриемуПлатежей);
|
||
МассивДанных.Добавить(Позиция.ДанныеАгента.ОператорПоПриемуПлатежей);
|
||
ШаблонОшибки = НСтр("ru = '%1 оператора по приему платежей в строке %2 не равен этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Телефон", ШаблонОшибки);
|
||
|
||
МассивДанных.Очистить();
|
||
МассивДанных.Добавить(ДанныеЧека.ДанныеАгента.ПлатежныйАгент);
|
||
МассивДанных.Добавить(Позиция.ДанныеАгента.ПлатежныйАгент);
|
||
ШаблонОшибки = НСтр("ru = '%1 платежного агента в строке %2 не равен этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Телефон", ШаблонОшибки);
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Операция", ШаблонОшибки);
|
||
|
||
МассивДанных.Очистить();
|
||
МассивДанных.Добавить(ДанныеЧека.ДанныеПоставщика);
|
||
МассивДанных.Добавить(Позиция.ДанныеПоставщика);
|
||
ШаблонОшибки = НСтр("ru = '%1 поставщика в строке %2 не равен этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Телефон", ШаблонОшибки);
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "ИНН", ШаблонОшибки);
|
||
ШаблонОшибки = НСтр("ru = '%1 поставщика в строке %2 не равно этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Наименование", ШаблонОшибки);
|
||
КонецЕсли;
|
||
КонецПроцедуры
|
||
|
||
// Выполняет проверку заполнения данных поставщика
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки.
|
||
// ДанныеЧека - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// Позиция - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыФискальнойСтрокиЧека
|
||
//
|
||
Процедура ПроверитьДанныеПоставщика(Проверка, ДанныеЧека, Позиция)
|
||
|
||
Если ЗаполненРеквизит(Проверка, Позиция, "ПризнакАгентаПоПредметуРасчета") Тогда
|
||
|
||
МассивДанных = Новый Массив();
|
||
МассивДанных.Добавить(ДанныеЧека.ДанныеПоставщика);
|
||
МассивДанных.Добавить(Позиция.ДанныеПоставщика);
|
||
|
||
ШаблонОшибки = НСтр("ru = '%1 поставщика в строке %2 не равен этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Телефон", ШаблонОшибки);
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "ИНН", ШаблонОшибки);
|
||
ШаблонОшибки = НСтр("ru = '%1 поставщика в строке %2 не равно этому значению в шапке.'");
|
||
ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, "Наименование", ШаблонОшибки);
|
||
|
||
КонецЕсли;
|
||
КонецПроцедуры
|
||
|
||
// Выполняет проверку оплаты
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки
|
||
// СуммыПозиций - см. ПараметрыСуммыПозиций
|
||
// СуммыОплат - см. ПараметрыСуммыОплат
|
||
Процедура ПроверитьСуммыОплат(Проверка, СуммыПозиций, СуммыОплат)
|
||
|
||
Если СуммыПозиций.Общая > СуммыОплат.Общая Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Сумма товарных позиций больше суммы оплат'"));
|
||
ИначеЕсли СуммыОплат.Общая > СуммыПозиций.Общая Тогда
|
||
Если (СуммыОплат.Общая - СуммыОплат.Наличные) > СуммыПозиций.Общая Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Сумма безналичных оплат больше суммы товарных позиций'"));
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
// Выполняет проверку фактической оплаты
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки
|
||
// СуммыПозиций - см. ПараметрыСуммыПозиций
|
||
// СуммыОплат - см. ПараметрыСуммыОплат
|
||
Процедура ПроверитьСуммуФактическихОплат(Проверка, СуммыПозиций, СуммыОплат)
|
||
|
||
СуммаФактическихОплат = СуммыОплат.НаличныеБезСдачи + СуммыОплат.Электронно + СуммыОплат.ВстречноеПредоставление
|
||
- СуммыПозиций.ПолнаяОплата;
|
||
Если СуммаФактическихОплат < 0 Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Сумма по строкам с указанием признака полной оплаты меньше чем сумма самих оплат'"));
|
||
ИначеЕсли СуммаФактическихОплат = 0 Тогда
|
||
Проверка.Ошибки.Добавить(НСтр("ru = 'Необходимо указать оплату'"));
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
#КонецОбласти
|
||
|
||
#Область ПроцедурыИФункцииДляПриведенияКФормату
|
||
|
||
Процедура ПривестиЕслиСпособРасчетаБезПередачиТовара(Позиция, ИсправленыОсновныеПараметры)
|
||
|
||
ПризнакСпособаРасчета = Позиция.ПризнакСпособаРасчета;
|
||
Если ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаЧастичная
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ОплатаКредита
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.Аванс
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаПолная Тогда
|
||
Позиция.ЕдиницаИзмерения = "Платеж";
|
||
Позиция.Количество = 1;
|
||
Позиция.Цена = Позиция.Сумма;
|
||
Позиция.ЦенаСоСкидками = Позиция.Сумма;
|
||
Позиция.СуммаСкидок = 0;
|
||
Позиция.ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.ПлатежВыплата;
|
||
ИсправленыОсновныеПараметры = Истина;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПривестиСтавкиНДС(Позиция)
|
||
|
||
ПризнакСпособаРасчета = Позиция.ПризнакСпособаРасчета;
|
||
Если ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаЧастичная
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.Аванс
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаПолная Тогда
|
||
Если Позиция.СтавкаНДС = Неопределено Тогда
|
||
Позиция.СуммаНДС = 0;
|
||
ИначеЕсли Позиция.СтавкаНДС > 0 И Позиция.СтавкаНДС < 100 Тогда
|
||
Позиция.СтавкаНДС = 100 + Позиция.СтавкаНДС;
|
||
КонецЕсли;
|
||
ИначеЕсли ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ОплатаКредита Тогда
|
||
Позиция.СтавкаНДС = Неопределено;
|
||
Позиция.СуммаНДС = 0;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
// Приводит суммы позиций чека к сумме полной оплаты
|
||
//
|
||
// Параметры:
|
||
// ОсновныеПараметры - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыОперацииФискализацииЧека
|
||
// СуммыПозиций - см. ПараметрыСуммыПозиций
|
||
// СуммыОплат - см. ПараметрыСуммыОплат
|
||
//
|
||
Процедура ПривестиСуммыПозицийЧекаКСуммеТаблицыОплат(ОсновныеПараметры, СуммыПозиций, СуммыОплат)
|
||
|
||
СуммаФактическихОплат = СуммыОплат.НаличныеБезСдачи + СуммыОплат.Электронно + СуммыОплат.ВстречноеПредоставление;
|
||
СуммаФактическихОплат = СуммаФактическихОплат - СуммыПозиций.ПолнаяОплата;
|
||
СуммаНеобходимойПолнойОплаты = СуммыПозиций.Общая - СуммыПозиций.ПередачаБезОплаты - СуммыПозиций.ПолнаяОплата;
|
||
|
||
// Сумма всегда больше нулю, т.к. в чеке есть строки в частичной оплатой
|
||
Если СуммаФактическихОплат < СуммаНеобходимойПолнойОплаты Тогда
|
||
Коэффициент = СуммаФактическихОплат / СуммаНеобходимойПолнойОплаты;
|
||
МаксимальнаяСумма = 0;
|
||
РассчитаннаяСуммаЧека = 0;
|
||
ПозицияСМаксимальнойСуммой = Неопределено;
|
||
Для Каждого Позиция Из ОсновныеПараметры.ПозицииЧека Цикл
|
||
Если Позиция.Свойство("ФискальнаяСтрока") Тогда
|
||
ПризнакСпособаРасчета = Позиция.ПризнакСпособаРасчета;
|
||
Если ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаЧастичная
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ОплатаКредита Тогда
|
||
Если Позиция.Сумма > МаксимальнаяСумма Тогда
|
||
МаксимальнаяСумма = Позиция.Сумма;
|
||
ПозицияСМаксимальнойСуммой = Позиция;
|
||
КонецЕсли;
|
||
ПриведеннаяСумма = Окр(Позиция.Сумма * Коэффициент,2,1);
|
||
Позиция.Сумма = ПриведеннаяСумма;
|
||
Позиция.Цена = ПриведеннаяСумма;
|
||
Позиция.ЦенаСоСкидками = ПриведеннаяСумма;
|
||
РассчитаннаяСуммаЧека = РассчитаннаяСуммаЧека + ПриведеннаяСумма;
|
||
Если Позиция.СуммаНДС <> Неопределено Тогда
|
||
Позиция.СуммаНДС = Окр(Позиция.СуммаНДС * Коэффициент,2,1);
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
Иначе
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
Отклонение = СуммаФактическихОплат - РассчитаннаяСуммаЧека;
|
||
|
||
Если Макс(Отклонение, -Отклонение) >= 0.01 Тогда
|
||
Позиция = ПозицияСМаксимальнойСуммой;
|
||
Сумма = Позиция.Сумма;
|
||
СуммаСОтклонением = Позиция.Сумма + Отклонение;
|
||
Позиция.Цена = СуммаСОтклонением;
|
||
Позиция.Сумма = СуммаСОтклонением;
|
||
Позиция.ЦенаСоСкидками = СуммаСОтклонением;
|
||
|
||
Если Позиция.СуммаНДС <> Неопределено И Сумма > 0 Тогда
|
||
// Максимальная сумма не может быть равна или меньше нуля
|
||
// Определяем отклонение НДС
|
||
Позиция.СуммаНДС = Окр(СуммаСОтклонением * Позиция.СуммаНДС / Сумма, 2,1);
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
// Общие суммы НДС по ставкам пересчитывается далее по алгоритму.
|
||
|
||
// ИсправитьТаблицуОплат
|
||
СуммаИсправленияОплат = СуммаНеобходимойПолнойОплаты - СуммаФактическихОплат;
|
||
Если СуммаИсправленияОплат > 0 Тогда
|
||
Для Каждого СтрокаОплат Из ОсновныеПараметры.ТаблицаОплат Цикл
|
||
ТипОплаты = СтрокаОплат.ТипОплаты;
|
||
Если ТипОплаты = Перечисления.ТипыОплатыККТ.Постоплата
|
||
Или ТипОплаты = Перечисления.ТипыОплатыККТ.Предоплата Тогда
|
||
|
||
Если СуммаИсправленияОплат >= СтрокаОплат.Сумма Тогда
|
||
СуммаИсправленияОплат = СуммаИсправленияОплат - СтрокаОплат.Сумма;
|
||
СтрокаОплат.Сумма = 0;
|
||
Иначе
|
||
СуммаИсправленияОплат = 0;
|
||
СтрокаОплат.Сумма = СтрокаОплат.Сумма - СуммаИсправленияОплат;
|
||
КонецЕсли;
|
||
Если СуммаИсправленияОплат <= 0 Тогда
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
КонецЕсли;
|
||
|
||
КоличествоЭлементов = ОсновныеПараметры.ТаблицаОплат.Количество();
|
||
Для Индекс = 1 По КоличествоЭлементов Цикл
|
||
Если ОсновныеПараметры.ТаблицаОплат[КоличествоЭлементов - Индекс].Сумма = 0 Тогда
|
||
ОсновныеПараметры.ТаблицаОплат.Удалить(КоличествоЭлементов - Индекс);
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
КонецПроцедуры
|
||
|
||
// Функция выполняет разделение фискальной строки.
|
||
//
|
||
Процедура РазделитьФискальнуюСтроку(ТекущаяПозиция, НовыеПозицииЧека, РасчетнаяЦена, РазницаСумм)
|
||
|
||
СтандартнаяОбработка = Истина;
|
||
ФорматноЛогическийКонтрольПереопределяемый.РазделитьФискальнуюСтроку(ТекущаяПозиция, НовыеПозицииЧека, РасчетнаяЦена, РазницаСумм, СтандартнаяОбработка);
|
||
Если Не СтандартнаяОбработка Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
// Запоминаем начальные значения.
|
||
КоличествоНачальное = ТекущаяПозиция.Количество;
|
||
СуммаСкидокНачальная = ТекущаяПозиция.СуммаСкидок;
|
||
СуммаНДСНачальная = ТекущаяПозиция.СуммаНДС; // Рассчитывается формально, т.к. сумма НДС текущими драйверами игнорируется.
|
||
СуммаНачальная = ТекущаяПозиция.Сумма;
|
||
|
||
// Если разница есть, то ее делим на копейку.
|
||
// Получаем количество, которое нужно переоценить.
|
||
КоличествоПереоценки = Окр(РазницаСумм / 0.01, 3, 1);
|
||
Если КоличествоПереоценки < 0 Тогда
|
||
КоличествоПереоценки = -КоличествоПереоценки;
|
||
КонецЕсли;
|
||
|
||
// Из начального количества отнимаем количество переоценки.
|
||
// Получаем количество, которое остается по расчетной цене.
|
||
КоличествоРасчетное = ТекущаяПозиция.Количество - КоличествоПереоценки;
|
||
|
||
// Цена переоценки во всех примерах отличается от расчетной на 1 копейку.
|
||
// В большую или меньшую сторону в зависимости от знака разницы - зависимость обратная.
|
||
ЦенаПереоценки = РасчетнаяЦена - Окр(РазницаСумм / КоличествоПереоценки, 2, 1);
|
||
|
||
// Теперь считаются суммы, т.к. по ним выполняется анализ коэффициента для пересчета
|
||
СуммаПереоценки = Окр(КоличествоПереоценки * ЦенаПереоценки, 2, 1);
|
||
СуммаРасчетная = Окр(КоличествоРасчетное * РасчетнаяЦена, 2, 1);
|
||
|
||
// Распределяем суммы скидок пропорционально количеству.
|
||
// Если суммы есть. А если их нет, то должно остаться Неопределено.
|
||
Если СуммаСкидокНачальная <> Неопределено Тогда
|
||
Если КоличествоПереоценки > КоличествоРасчетное Тогда
|
||
СуммаСкидокПереоценки = Окр(СуммаСкидокНачальная * КоличествоПереоценки / КоличествоНачальное, 2, 1);
|
||
СуммаСкидокРасчетная = СуммаСкидокНачальная - СуммаСкидокПереоценки;
|
||
Иначе
|
||
СуммаСкидокРасчетная = Окр(СуммаСкидокНачальная * КоличествоРасчетное / КоличествоНачальное, 2, 1);
|
||
СуммаСкидокПереоценки = СуммаСкидокНачальная - СуммаСкидокРасчетная;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
// А суммы распределяем НДС пропорционально суммам.
|
||
// Потому что распределение пропорционально количеству.
|
||
// Вызывает расхождения в некоторых критичных ситуациях.
|
||
// Если суммы есть. А если их нет, то должно остаться Неопределено.
|
||
Если СуммаНДСНачальная <> Неопределено Тогда
|
||
Если СуммаПереоценки > СуммаРасчетная Тогда
|
||
СуммаНДСПереоценки = Окр(СуммаНДСНачальная * СуммаПереоценки / СуммаНачальная, 2, 1);
|
||
СуммаНДСРасчетная = СуммаНДСНачальная - СуммаНДСПереоценки;
|
||
Иначе
|
||
СуммаНДСРасчетная = Окр(СуммаНДСНачальная * СуммаРасчетная / СуммаНачальная, 2, 1);
|
||
СуммаНДСПереоценки = СуммаНДСНачальная - СуммаНДСРасчетная;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
// Выводим вместо первоначальной строки две новых.
|
||
// Сначала с расчетной ценой и остатком количества.
|
||
// И суммой - произведение цены и количества.
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
НоваяПозиция.Количество = КоличествоРасчетное;
|
||
НоваяПозиция.ЦенаСоСкидками = РасчетнаяЦена;
|
||
НоваяПозиция.Сумма = СуммаРасчетная;
|
||
Если СуммаСкидокНачальная <> Неопределено Тогда
|
||
НоваяПозиция.СуммаСкидок = СуммаСкидокНачальная - СуммаСкидокПереоценки;
|
||
КонецЕсли;
|
||
Если СуммаНДСНачальная <> Неопределено Тогда
|
||
НоваяПозиция.СуммаНДС = СуммаНДСРасчетная;
|
||
КонецЕсли;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
|
||
// Потом с переоцененной ценой и переоцененным количеством.
|
||
// И суммой - произведение цены и количества.
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
НоваяПозиция.Количество = КоличествоПереоценки;
|
||
НоваяПозиция.ЦенаСоСкидками = ЦенаПереоценки;
|
||
НоваяПозиция.Сумма = СуммаПереоценки;
|
||
Если СуммаСкидокНачальная <> Неопределено Тогда
|
||
НоваяПозиция.СуммаСкидок = СуммаСкидокПереоценки;
|
||
КонецЕсли;
|
||
Если СуммаНДСНачальная <> Неопределено Тогда
|
||
НоваяПозиция.СуммаНДС = СуммаНДСПереоценки;
|
||
КонецЕсли;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПривестиПозицииЧекаПоАлгоритмуРазделятьСтроки(ПозицииЧека, НовыеПозицииЧека, ДопустимоеРасхождение)
|
||
|
||
Для Каждого ТекущаяПозиция Из ПозицииЧека Цикл
|
||
Если Не ТекущаяПозиция.Свойство("ФискальнаяСтрока") Тогда
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
КонецЕсли;
|
||
|
||
Количество = ?(ТекущаяПозиция.Количество = 0, 1, ТекущаяПозиция.Количество);
|
||
Если Количество = 1 Тогда
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
НоваяПозиция.ЦенаСоСкидками = НоваяПозиция.Сумма;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
КонецЕсли;
|
||
НоваяСуммаБезОкругления = Количество * ТекущаяПозиция.ЦенаСоСкидками;
|
||
Сумма = ТекущаяПозиция.Сумма;
|
||
РазницаСуммДляПроверки = НоваяСуммаБезОкругления - Сумма;
|
||
// Получаем расчетную цену с учетом скидок делением входящей суммы на входящее количество.
|
||
РасчетнаяЦена = Окр(Сумма / Количество, 2, 1);
|
||
// Здесь и далее все цены и суммы округляем до 2 знаков после запятой, количества - до 3 знаков.
|
||
// Умножаем входящее количество на расчетную цену и получаем новую промежуточную сумму.
|
||
НоваяСумма = Окр(Количество * РасчетнаяЦена, 2, 1);
|
||
// Вычисляем разницу между промежуточной и входящей суммой.
|
||
РазницаСумм = НоваяСумма - Сумма;
|
||
Если Окр(ТекущаяПозиция.ЦенаСоСкидками * Количество, 2, 1) = ТекущаяПозиция.Сумма Тогда
|
||
// Цену не пересчитываем.
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
ИначеЕсли РазницаСуммДляПроверки >= -ДопустимоеРасхождение И РазницаСуммДляПроверки <= ДопустимоеРасхождение Тогда
|
||
// Если разница допустима - оставляем одну строку.
|
||
// Если разницы нет - оставляем одну строку.
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
// Но подменяем расчетную цену.
|
||
НоваяПозиция.ЦенаСоСкидками = РасчетнаяЦена;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
ИначеЕсли РазницаСумм = 0 Тогда
|
||
// Если разница неокругленная есть, а округленной нет.
|
||
// То передаем в ККТ как есть - оставляем одну строку.
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
// Но подменяем расчетную цену.
|
||
НоваяПозиция.ЦенаСоСкидками = РасчетнаяЦена;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
Иначе
|
||
// Разделяем строку.
|
||
РазделитьФискальнуюСтроку(ТекущаяПозиция, НовыеПозицииЧека, РасчетнаяЦена, РазницаСумм);
|
||
КонецЕсли;
|
||
|
||
КонецЦикла;
|
||
КонецПроцедуры
|
||
|
||
Процедура ПривестиПозицииЧекаПоАлгоритмуЗачитыватьСуммы(ПозицииЧека, НовыеПозицииЧека, ДопустимоеРасхождение)
|
||
|
||
СтрокиПоложительные = Новый Массив;
|
||
СтрокиОтрицательные = Новый Массив;
|
||
СтрокаПоследнегоТовара = 0;
|
||
|
||
Для Каждого ТекущаяПозиция Из ПозицииЧека Цикл
|
||
Если Не ТекущаяПозиция.Свойство("ФискальнаяСтрока") Тогда
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
Если СтрокаПоследнегоТовара = 0 Тогда
|
||
НоваяПозиция.Вставить("СтрокаПоследнегоТовара", 0);
|
||
Иначе
|
||
НоваяПозиция.Вставить("СтрокаПоследнегоТовара", 99999);
|
||
КонецЕсли;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
КонецЕсли;
|
||
|
||
СтрокаПоследнегоТовара = ТекущаяПозиция.НомерСтрокиТовара;
|
||
Количество = ?(ТекущаяПозиция.Количество = 0, 1, ТекущаяПозиция.Количество);
|
||
Если Количество = 1 Тогда
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
НоваяПозиция.ЦенаСоСкидками = НоваяПозиция.Сумма;
|
||
НоваяПозиция.Вставить("СтрокаПоследнегоТовара", СтрокаПоследнегоТовара);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
КонецЕсли;
|
||
|
||
НоваяСуммаБезОкругления = Количество * ТекущаяПозиция.ЦенаСоСкидками;
|
||
Сумма = ТекущаяПозиция.Сумма;
|
||
РазницаСуммДляПроверки = НоваяСуммаБезОкругления - Сумма;
|
||
// Получаем расчетную цену с учетом скидок делением входящей суммы на входящее количество.
|
||
РасчетнаяЦена = Окр(Сумма / Количество, 2, 1);
|
||
// Здесь и далее все цены и суммы округляем до 2 знаков после запятой, количества - до 3 знаков.
|
||
// Умножаем входящее количество на расчетную цену и получаем новую промежуточную сумму.
|
||
НоваяСумма = Окр(Количество * РасчетнаяЦена, 2, 1);
|
||
// Вычисляем разницу между промежуточной и входящей суммой.
|
||
РазницаСумм = НоваяСумма - Сумма;
|
||
|
||
НоваяПозиция = СкопироватьСтруктуру(ТекущаяПозиция);
|
||
НоваяПозиция.Вставить("РасчетнаяЦена", РасчетнаяЦена);
|
||
НоваяПозиция.Вставить("РазницаСумм", РазницаСумм);
|
||
НоваяПозиция.Вставить("РазницаСуммДляПроверки", РазницаСуммДляПроверки);
|
||
НоваяПозиция.Вставить("СтрокаПоследнегоТовара", СтрокаПоследнегоТовара);
|
||
Если Окр(ТекущаяПозиция.ЦенаСоСкидками * Количество, 2, 1) = ТекущаяПозиция.Сумма Тогда
|
||
// Строку оставляем в первоначальном виде.
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
ИначеЕсли РазницаСуммДляПроверки >= -ДопустимоеРасхождение И РазницаСуммДляПроверки <= ДопустимоеРасхождение Тогда
|
||
// Если разница допустима - оставляем одну строку.
|
||
// Но подменяем расчетную цену.
|
||
НоваяПозиция.ЦенаСоСкидками = РасчетнаяЦена;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
ИначеЕсли РазницаСумм = 0 Тогда
|
||
// Если разница неокругленная есть, а округленной нет.
|
||
// То передаем в ККТ как есть - оставляем одну строку.
|
||
// Но подменяем расчетную цену.
|
||
НоваяПозиция.ЦенаСоСкидками = РасчетнаяЦена;
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Продолжить;
|
||
ИначеЕсли РазницаСумм > 0 Тогда
|
||
// Если разница есть, то строку с положительной разницей добавляем в массив положительных строк.
|
||
СтрокиПоложительные.Добавить(НоваяПозиция);
|
||
Иначе
|
||
// Если разница есть, то строку с отрицательной разницей добавляем в массив отрицательных строк.
|
||
НоваяПозиция.РазницаСумм = -РазницаСумм;
|
||
СтрокиОтрицательные.Добавить(НоваяПозиция);
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
ИндексПоложительных = СтрокиПоложительные.ВГраница();
|
||
ИндексОтрицательных = СтрокиОтрицательные.ВГраница();
|
||
Если ИндексПоложительных >= 0 И ИндексОтрицательных >= 0 Тогда
|
||
// В массиве положительных и отрицательных.
|
||
// Находим строки с совпадающей по модулю сумой расхождения.
|
||
// Строки идут одна к одному.
|
||
СдвигПоложительного = 0;
|
||
Для СчетчикПоложительный = 0 По ИндексПоложительных Цикл
|
||
ПоложительнаяСтрока = СтрокиПоложительные[СчетчикПоложительный - СдвигПоложительного];
|
||
СдвигОтрицательного = 0;
|
||
ИндексОтрицательных = СтрокиОтрицательные.ВГраница();
|
||
Для СчетчикОтрицательный = 0 По ИндексОтрицательных Цикл
|
||
ОтрицательнаяСтрока = СтрокиОтрицательные[СчетчикОтрицательный - СдвигОтрицательного];
|
||
Если ПоложительнаяСтрока.РазницаСумм = ОтрицательнаяСтрока.РазницаСумм Тогда
|
||
// Перекрываем разницу по совпадающим строкам из одного массива суммами другого.
|
||
// Увеличивая сумму в положительной строке и уменьшая в отрицательной.
|
||
ПоложительнаяСтрока.Сумма = ПоложительнаяСтрока.Сумма + ПоложительнаяСтрока.РазницаСумм;
|
||
ОтрицательнаяСтрока.Сумма = ОтрицательнаяСтрока.Сумма - ПоложительнаяСтрока.РазницаСумм;
|
||
|
||
// Перекрытые строки переносим в массив для печати и удаляем из массивов.
|
||
НоваяПозиция = СкопироватьСтруктуру(ПоложительнаяСтрока);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
|
||
НоваяПозиция = СкопироватьСтруктуру(ОтрицательнаяСтрока);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
|
||
СтрокиПоложительные.Удалить(СчетчикПоложительный - СдвигПоложительного);
|
||
СтрокиОтрицательные.Удалить(СчетчикОтрицательный - СдвигОтрицательного);
|
||
|
||
СдвигПоложительного = СдвигПоложительного + 1;
|
||
СдвигОтрицательного = СдвигОтрицательного + 1;
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
Если ИндексПоложительных < 0 Тогда
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
КонецЕсли;
|
||
|
||
ИндексПоложительных = СтрокиПоложительные.ВГраница();
|
||
ИндексОтрицательных = СтрокиОтрицательные.ВГраница();
|
||
Если ИндексПоложительных >= 0 И ИндексОтрицательных >= 0 Тогда
|
||
// Обходим строки положительного массива.
|
||
// Увеличивая сумму в каждой из них на сумму расхождения.
|
||
// Которую распределяем по строкам с отрицательным расхождением, уменьшая сумму там.
|
||
СдвигПоложительного = 0;
|
||
Для СчетчикПоложительный = 0 По ИндексПоложительных Цикл
|
||
ПоложительнаяСтрока = СтрокиПоложительные[СчетчикПоложительный - СдвигПоложительного];
|
||
Если ПоложительнаяСтрока.РазницаСумм <= ДопустимоеРасхождение Тогда
|
||
// Разница сумм в строке всегда по модулю.
|
||
Продолжить;
|
||
КонецЕсли;
|
||
СдвигОтрицательного = 0;
|
||
ИндексОтрицательных = СтрокиОтрицательные.ВГраница();
|
||
Для СчетчикОтрицательный = 0 По ИндексОтрицательных Цикл
|
||
ОтрицательнаяСтрока = СтрокиОтрицательные[СчетчикОтрицательный - СдвигОтрицательного];
|
||
Если ОтрицательнаяСтрока.РазницаСумм <= ДопустимоеРасхождение
|
||
И ОтрицательнаяСтрока.РазницаСумм <> ПоложительнаяСтрока.РазницаСумм Тогда
|
||
// Разница сумм в строке всегда по модулю.
|
||
Продолжить;
|
||
КонецЕсли;
|
||
// Перекрываем разницу по совпадающим строкам из одного массива суммами другого.
|
||
// Увеличивая сумму в положительной строке и уменьшая в отрицательной.
|
||
|
||
Если ПоложительнаяСтрока.РазницаСумм > ОтрицательнаяСтрока.РазницаСумм Тогда
|
||
ПоложительнаяСтрока.Сумма = ПоложительнаяСтрока.Сумма + ОтрицательнаяСтрока.РазницаСумм;
|
||
ОтрицательнаяСтрока.Сумма = ОтрицательнаяСтрока.Сумма - ОтрицательнаяСтрока.РазницаСумм;
|
||
// Уменьшаем остаток разницы положительной строки
|
||
ПоложительнаяСтрока.РазницаСумм = ПоложительнаяСтрока.РазницаСумм - ОтрицательнаяСтрока.РазницаСумм;
|
||
// Перекрытую строку переносим в массив для печати.
|
||
|
||
НоваяПозиция = СкопироватьСтруктуру(ОтрицательнаяСтрока);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
|
||
// И удаляем из массивов.
|
||
СтрокиОтрицательные.Удалить(СчетчикОтрицательный - СдвигОтрицательного);
|
||
// Сдвигаем отрицательные счетчики
|
||
СдвигОтрицательного = СдвигОтрицательного + 1;
|
||
|
||
Иначе
|
||
|
||
НадоУдалятьОтрицательные = ПоложительнаяСтрока.РазницаСумм = ОтрицательнаяСтрока.РазницаСумм;
|
||
|
||
ПоложительнаяСтрока.Сумма = ПоложительнаяСтрока.Сумма + ПоложительнаяСтрока.РазницаСумм;
|
||
ОтрицательнаяСтрока.Сумма = ОтрицательнаяСтрока.Сумма - ПоложительнаяСтрока.РазницаСумм;
|
||
// Уменьшаем остаток разницы положительной строки
|
||
ОтрицательнаяСтрока.РазницаСумм = ОтрицательнаяСтрока.РазницаСумм - ПоложительнаяСтрока.РазницаСумм;
|
||
// Перекрытую строку переносим в массив для печати.
|
||
|
||
НоваяПозиция = СкопироватьСтруктуру(ПоложительнаяСтрока);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
Если НадоУдалятьОтрицательные Тогда
|
||
НоваяПозиция = СкопироватьСтруктуру(ОтрицательнаяСтрока);
|
||
НовыеПозицииЧека.Добавить(НоваяПозиция);
|
||
КонецЕсли;
|
||
|
||
// И удаляем из массивов.
|
||
СтрокиПоложительные.Удалить(СчетчикПоложительный - СдвигПоложительного);
|
||
// Сдвигаем положительные счетчики
|
||
СдвигПоложительного = СдвигПоложительного + 1;
|
||
|
||
Если НадоУдалятьОтрицательные Тогда
|
||
// И удаляем из массивов.
|
||
СтрокиОтрицательные.Удалить(СчетчикОтрицательный - СдвигОтрицательного);
|
||
// Сдвигаем отрицательные счетчики
|
||
СдвигОтрицательного = СдвигОтрицательного + 1;
|
||
КонецЕсли;
|
||
|
||
// Отрицательный цикл прерываем.
|
||
// Ибо закрывать текущую строку придется следующей положительной.
|
||
// Если она есть.
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
Если ИндексПоложительных < 0 Тогда
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
КонецЕсли;
|
||
|
||
ИндексПоложительных = СтрокиПоложительные.ВГраница();
|
||
// Оставшиеся строки обоих массивов разделяются.
|
||
// Каждая на две по первому алгоритму и добавляются в массив для печати.
|
||
Если ИндексПоложительных >= 0 Тогда
|
||
Для Каждого ТекущаяПозиция Из СтрокиПоложительные Цикл
|
||
// Еще раз пересчитываем разницу
|
||
// Получаем расчетную цену с учетом скидок делением входящей суммы на входящее количество.
|
||
РасчетнаяЦена = Окр(ТекущаяПозиция.Сумма / ТекущаяПозиция.Количество, 2, 1);
|
||
// Здесь и далее все цены и суммы округляем до 2 знаков после запятой, количества - до 3 знаков.
|
||
// Умножаем входящее количество на расчетную цену и получаем новую промежуточную сумму.
|
||
НоваяСумма = Окр(ТекущаяПозиция.Количество * РасчетнаяЦена, 2, 1);
|
||
// Вычисляем разницу между промежуточной и входящей суммой.
|
||
РазницаСумм = НоваяСумма - ТекущаяПозиция.Сумма;
|
||
Если ТекущаяПозиция.РазницаСуммДляПроверки >= -ДопустимоеРасхождение И ТекущаяПозиция.РазницаСуммДляПроверки <= ДопустимоеРасхождение Тогда
|
||
// Если разница допустима - оставляем одну строку.
|
||
НовыеПозицииЧека.Добавить(ТекущаяПозиция);
|
||
ИначеЕсли РазницаСумм = 0 Тогда
|
||
// Если разница неокругленная есть, а округленной нет.
|
||
// То передаем в ККТ как есть - оставляем одну строку.
|
||
НовыеПозицииЧека.Добавить(ТекущаяПозиция);
|
||
Иначе
|
||
// Разделяем строку.
|
||
РазделитьФискальнуюСтроку(ТекущаяПозиция, НовыеПозицииЧека, РасчетнаяЦена, РазницаСумм);
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
КонецЕсли;
|
||
|
||
ИндексОтрицательных = СтрокиОтрицательные.ВГраница();
|
||
Если ИндексОтрицательных >= 0 Тогда
|
||
Для Каждого ТекущаяПозиция Из СтрокиОтрицательные Цикл
|
||
// Еще раз пересчитываем разницу
|
||
// Получаем расчетную цену с учетом скидок делением входящей суммы на входящее количество.
|
||
РасчетнаяЦена = Окр(ТекущаяПозиция.Сумма / ТекущаяПозиция.Количество, 2, 1);
|
||
// Здесь и далее все цены и суммы округляем до 2 знаков после запятой, количества - до 3 знаков.
|
||
// Умножаем входящее количество на расчетную цену и получаем новую промежуточную сумму.
|
||
НоваяСумма = Окр(ТекущаяПозиция.Количество * РасчетнаяЦена, 2, 1);
|
||
// Вычисляем разницу между промежуточной и входящей суммой.
|
||
РазницаСумм = НоваяСумма - ТекущаяПозиция.Сумма;
|
||
Если ТекущаяПозиция.РазницаСуммДляПроверки >= -ДопустимоеРасхождение И ТекущаяПозиция.РазницаСуммДляПроверки <= ДопустимоеРасхождение Тогда
|
||
// Если разница допустима - оставляем одну строку.
|
||
НовыеПозицииЧека.Добавить(ТекущаяПозиция);
|
||
ИначеЕсли РазницаСумм = 0 Тогда
|
||
// Если разница неокругленная есть, а округленной нет.
|
||
// То передаем в ККТ как есть - оставляем одну строку.
|
||
НовыеПозицииЧека.Добавить(ТекущаяПозиция);
|
||
Иначе
|
||
// Разделяем строку.
|
||
РазделитьФискальнуюСтроку(ТекущаяПозиция, НовыеПозицииЧека, РасчетнаяЦена, РазницаСумм);
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
КонецЕсли;
|
||
// Массив для печати сортируется по первоначальному номеру строки.
|
||
СортироватьМассивФискальныхСтрок(НовыеПозицииЧека);
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПривестиАдресИМестоРасчетов(ДанныеЧека, ПараметрыРегистрации)
|
||
|
||
Если ПараметрыРегистрации = Неопределено Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
Если Не ЗначениеЗаполнено(ДанныеЧека.АдресРасчетов) Тогда
|
||
ДанныеЧека.АдресРасчетов = ПараметрыРегистрации.АдресПроведенияРасчетов;
|
||
КонецЕсли;
|
||
|
||
Если Не ЗначениеЗаполнено(ДанныеЧека.МестоРасчетов) Тогда
|
||
ДанныеЧека.МестоРасчетов = ПараметрыРегистрации.МестоПроведенияРасчетов;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
#КонецОбласти
|
||
|
||
#Область ВспомогательныеПроцедурыИФункции
|
||
|
||
// Увеличивает номер позиции в структуре проверки
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки
|
||
//
|
||
Процедура УвеличитьНомерПозиции(Проверка)
|
||
Проверка.НомерПозиции = Проверка.НомерПозиции + 1;
|
||
КонецПроцедуры
|
||
|
||
// Формирует текст ошибки подставляя имя реквизита и номер позиции
|
||
//
|
||
// Параметры:
|
||
// ШаблонОшибки - Строка
|
||
// ИмяРеквизита - Строка
|
||
// НомерПозиции - Строка
|
||
//
|
||
Функция ТекстОшибки(ШаблонОшибки, Знач ИмяРеквизита, Знач НомерПозиции)
|
||
|
||
НомерПозиции = Формат(НомерПозиции, "ЧГ=0");
|
||
Ошибка = СтрЗаменить(ШаблонОшибки,"%1", ИмяРеквизита);
|
||
Ошибка = СтрЗаменить(Ошибка,"%2", НомерПозиции);
|
||
Возврат Ошибка;
|
||
|
||
КонецФункции
|
||
|
||
#КонецОбласти
|
||
|
||
#Область ПроцедурыИФункцииДляПроверки
|
||
|
||
// Выполняет проверку на соответствие формата фискальных документов
|
||
//
|
||
// Параметры:
|
||
// Проверка - см. ПараметрыПроверки
|
||
// ВерсииФФД - Неопределено, Строка - версия на которую нужно проверить, может быть указано несколько если задано Неопределено, тогда любая версия ФФД
|
||
//
|
||
Функция ВерсияФФД(Проверка, ВерсииФФД = Неопределено)
|
||
|
||
Если ВерсииФФД = Неопределено Тогда
|
||
Возврат Истина;
|
||
КонецЕсли;
|
||
|
||
Возврат СтрНайти(ВерсииФФД, Проверка.ВерсияФФД)>0;
|
||
|
||
КонецФункции
|
||
|
||
Функция ЕстьРеквизит(Проверка, Данные, Знач ИмяРеквизита, Значение)
|
||
|
||
Если Данные.Свойство(ИмяРеквизита, Значение) Тогда
|
||
Возврат Истина;
|
||
КонецЕсли;
|
||
|
||
Проверка.Ошибки.Добавить(СтрШаблон(НСтр("ru = 'Реквизит %1 отсутствует.'"), ИмяРеквизита));
|
||
Возврат Ложь;
|
||
|
||
КонецФункции
|
||
|
||
Функция ЗаполненРеквизит(Проверка, Данные, Знач ИмяРеквизита)
|
||
|
||
Значение = Неопределено;
|
||
Если ЕстьРеквизит(Проверка, Данные, ИмяРеквизита, Значение) Тогда
|
||
Возврат ЗначениеЗаполнено(Значение);
|
||
КонецЕсли;
|
||
Возврат Ложь;
|
||
|
||
КонецФункции
|
||
|
||
Процедура ПроверитьРеквизит(Проверка, Данные, Знач ИмяРеквизита = Неопределено, Знач ВерсииФФД = Неопределено, Знач ШаблонОшибки = Неопределено)
|
||
|
||
Если Не ВерсияФФД(Проверка, ВерсииФФД) Тогда
|
||
Возврат;
|
||
КонецЕсли;
|
||
|
||
Значение = Неопределено;
|
||
Если ЕстьРеквизит(Проверка, Данные, ИмяРеквизита, Значение) Тогда
|
||
Если Не ЗначениеЗаполнено(Значение) Тогда
|
||
Если ЗначениеЗаполнено(Проверка.НомерПозиции) Тогда
|
||
ШаблонОшибки = ?(ШаблонОшибки = Неопределено, НСтр("ru = '%1 не заполнен в строке №%2.'"), ШаблонОшибки);
|
||
Иначе
|
||
ШаблонОшибки = ?(ШаблонОшибки = Неопределено, НСтр("ru = '%1 не заполнен.'"), ШаблонОшибки);
|
||
КонецЕсли;
|
||
Идентификатор = ОбщегоНазначенияБПОКлиентСервер.ПредставлениеИдентификатора(ИмяРеквизита);
|
||
Идентификатор = ВРег(Лев(Идентификатор,1)) + Сред(Идентификатор,2);
|
||
Проверка.Ошибки.Добавить(ТекстОшибки(ШаблонОшибки, Идентификатор, Проверка.НомерПозиции));
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПроверитьРеквизитВМассивеДанных(Проверка, МассивДанных, Знач ИмяРеквизита = Неопределено, Знач ВерсииФФД = Неопределено, Знач ШаблонОшибки = Неопределено)
|
||
|
||
РеквизитЗаполнен = Ложь;
|
||
Для Каждого Данные Из МассивДанных Цикл
|
||
Значение = Неопределено;
|
||
Если ЕстьРеквизит(Проверка, Данные, ИмяРеквизита, Значение) И ЗначениеЗаполнено(Значение) Тогда
|
||
РеквизитЗаполнен = Истина;
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
Если Не РеквизитЗаполнен Тогда
|
||
ШаблонОшибки = ?(ШаблонОшибки = Неопределено,
|
||
НСтр("ru = 'Реквизит %1 не заполнен в шапке или в строке %2.'"),
|
||
ШаблонОшибки);
|
||
Проверка.Ошибки.Добавить(ТекстОшибки(ШаблонОшибки, ИмяРеквизита, Проверка.НомерПозиции));
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПроверитьСовпадениеРеквизитаВМассивеДанных(Проверка, МассивДанных, Знач ИмяРеквизита = Неопределено, Знач ШаблонОшибки = Неопределено)
|
||
|
||
РеквизитСовпадает = Истина;
|
||
ЗначениеРеквизита = Неопределено;
|
||
Для Каждого Данные Из МассивДанных Цикл
|
||
Значение = Неопределено;
|
||
Если ЕстьРеквизит(Проверка, Данные, ИмяРеквизита, Значение) И ЗначениеЗаполнено(Значение) Тогда
|
||
Если ЗначениеРеквизита = Неопределено Тогда
|
||
ЗначениеРеквизита = Значение;
|
||
ИначеЕсли ЗначениеРеквизита <> Значение Тогда
|
||
РеквизитСовпадает = Ложь;
|
||
Прервать;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
КонецЦикла;
|
||
|
||
Если Не РеквизитСовпадает Тогда
|
||
ШаблонОшибки = ?(ШаблонОшибки = Неопределено,
|
||
НСтр("ru = 'Значение реквизита %1 в строке %2 и шапке неравны.'"),
|
||
ШаблонОшибки);
|
||
Проверка.Ошибки.Добавить(ТекстОшибки(ШаблонОшибки, ИмяРеквизита, Проверка.НомерПозиции));
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПроверитьРеквизитИНН(Проверка, Данные, Знач ИмяРеквизита)
|
||
|
||
Значение = Неопределено;
|
||
Если ЕстьРеквизит(Проверка, Данные, ИмяРеквизита, Значение) Тогда
|
||
ОписаниеОшибки = "";
|
||
Если ЗначениеЗаполнено(Значение)
|
||
И НЕ ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ИННСоответствуетТребованиям(Значение, Ложь, ОписаниеОшибки) Тогда
|
||
Проверка.Ошибки.Добавить(СтрШаблон(НСтр("ru = 'ИНН (%1) некорректен (%2)'"), ИмяРеквизита, ОписаниеОшибки));
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПроверитьДлинуРеквизита(Проверка, Данные, Знач ИмяРеквизита, Длина)
|
||
|
||
Ошибки = Проверка.Ошибки;
|
||
Значение = Неопределено;
|
||
Если ЕстьРеквизит(Проверка, Данные, ИмяРеквизита, Значение) Тогда
|
||
Если ЗначениеЗаполнено(Значение) И СтрДлина(Значение) > Длина Тогда
|
||
Ошибки.Добавить(СтрШаблон(НСтр("ru = 'Длинна реквизита (%1) превышает %2 символа'"), ИмяРеквизита, Длина));
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
|
||
КонецПроцедуры
|
||
|
||
// Возвращает структуру сумм позиций чека
|
||
//
|
||
// Возвращаемое значение:
|
||
// Структура
|
||
Функция ПараметрыСуммыПозиций()
|
||
|
||
Структура = Новый Структура();
|
||
Структура.Вставить("Общая", 0);
|
||
Структура.Вставить("ПолнаяОплата", 0);
|
||
Структура.Вставить("ПередачаБезОплаты", 0);
|
||
Возврат Структура;
|
||
|
||
КонецФункции
|
||
|
||
Функция ПараметрыСуммыОплат()
|
||
|
||
Структура = Новый Структура();
|
||
Структура.Вставить("Общая", 0);
|
||
Структура.Вставить("Наличные", 0);
|
||
Структура.Вставить("НаличныеБезСдачи", 0);
|
||
Структура.Вставить("Электронно", 0);
|
||
Структура.Вставить("ВстречноеПредоставление", 0);
|
||
Структура.Вставить("Предоплата", 0);
|
||
Структура.Вставить("Постоплата", 0);
|
||
Возврат Структура;
|
||
|
||
КонецФункции
|
||
|
||
// Вычисляет суммы позиций чека по позиции
|
||
//
|
||
// Параметры:
|
||
// СуммыПозицийЧека - см. ПараметрыСуммыПозицийЧека
|
||
// Позиция - см. ОборудованиеЧекопечатающиеУстройстваКлиентСервер.ПараметрыФискальнойСтрокиЧека
|
||
//
|
||
Процедура ВычислитьСуммыПозиций(СуммыПозицийЧека, Позиция)
|
||
|
||
ПризнакСпособаРасчета = Позиция.ПризнакСпособаРасчета;
|
||
Если ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.Аванс
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаПолная
|
||
Или ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПередачаСПолнойОплатой Тогда
|
||
СуммыПозицийЧека.ПолнаяОплата = СуммыПозицийЧека.ПолнаяОплата + Позиция.Сумма;
|
||
ИначеЕсли ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПередачаБезОплаты Тогда
|
||
СуммыПозицийЧека.ПередачаБезОплаты = СуммыПозицийЧека.ПередачаБезОплаты + Позиция.Сумма;
|
||
КонецЕсли;
|
||
СуммыПозицийЧека.Общая = СуммыПозицийЧека.Общая + Позиция.Сумма;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ВычислитьСуммыОплат(СуммыОплат, СтрокаОплат)
|
||
|
||
Если СтрокаОплат.ТипОплаты = ПредопределенноеЗначение("Перечисление.ТипыОплатыККТ.Наличные") Тогда
|
||
СуммыОплат.Наличные = СуммыОплат.Наличные + СтрокаОплат.Сумма;
|
||
ИначеЕсли СтрокаОплат.ТипОплаты = ПредопределенноеЗначение("Перечисление.ТипыОплатыККТ.Электронно") Тогда
|
||
СуммыОплат.Электронно = СуммыОплат.Электронно + СтрокаОплат.Сумма;
|
||
ИначеЕсли СтрокаОплат.ТипОплаты = ПредопределенноеЗначение("Перечисление.ТипыОплатыККТ.ВстречноеПредоставление") Тогда
|
||
СуммыОплат.ВстречноеПредоставление = СуммыОплат.ВстречноеПредоставление + СтрокаОплат.Сумма;
|
||
ИначеЕсли СтрокаОплат.ТипОплаты = ПредопределенноеЗначение("Перечисление.ТипыОплатыККТ.Предоплата") Тогда
|
||
СуммыОплат.Предоплата = СуммыОплат.Предоплата + СтрокаОплат.Сумма;
|
||
ИначеЕсли СтрокаОплат.ТипОплаты = ПредопределенноеЗначение("Перечисление.ТипыОплатыККТ.Постоплата") Тогда
|
||
СуммыОплат.Постоплата = СуммыОплат.Постоплата + СтрокаОплат.Сумма;
|
||
КонецЕсли;
|
||
СуммыОплат.Общая = СуммыОплат.Общая + СтрокаОплат.Сумма;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ВычислитьСуммуНаличныеБезСдачи(СуммыПозиций, СуммыОплат)
|
||
|
||
СуммыОплат.НаличныеБезСдачи = СуммыОплат.Наличные;
|
||
|
||
// Проверяем что сумма наличные указана со сдачей.
|
||
Если СуммыОплат.Общая > СуммыПозиций.Общая И СуммыОплат.Наличные > 0 Тогда
|
||
НаличныеСдача = СуммыОплат.Общая - СуммыПозиций.Общая;
|
||
Если СуммыОплат.Наличные > НаличныеСдача Тогда
|
||
СуммыОплат.НаличныеБезСдачи = СуммыОплат.Наличные - НаличныеСдача;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПреобразоватьСистемуНалогообложения(Проверка, Данные)
|
||
|
||
ИспользуетсяФН36 = Проверка.ИспользуетсяФН36;
|
||
// Проверка системы налогообложения
|
||
Если Проверка.ТипОборудования = Перечисления.ТипыПодключаемогоОборудования.ККТ Тогда
|
||
// Пользователи, переходящие с 01.01.2021 с ЕНВД на ОСН могут не менять систему налогообложения
|
||
// в настройках кассы, если используют фискальный накопитель со сроком действия 36 мес.
|
||
// Подробнее см. Письмо ФНС России от 03.12.2020 № АБ-4-20/19907@.
|
||
Если ИспользуетсяФН36 И Данные.СистемаНалогообложения = Перечисления.ТипыСистемНалогообложенияККТ.ОСН Тогда
|
||
// Если в фискализируемом в чеке приходит – ОСН и для ККТ установлена галка «Используется ФН 36 мес.(ЕНВД)» меняем ОСН на ЕНВД.
|
||
Данные.СистемаНалогообложения = Перечисления.ТипыСистемНалогообложенияККТ.ЕНВД;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
Процедура ПреобразоватьПризнакПредметаРасчета(Проверка, Данные)
|
||
|
||
Если Не ВерсияФФД(Проверка, "1.2") Тогда
|
||
// Значения доступные только в ФФД 1.2 преобразуем в значения доступные в ФФД 1.1, 1.05
|
||
ПризнакПредметаРасчета = Данные.ПризнакПредметаРасчета;
|
||
Если ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.ПодакцизныйТоварМаркируемыйСИНеИмеющийКМ
|
||
Или ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.ПодакцизныйТоварМаркируемыйСИИмеющийКМ Тогда
|
||
Данные.ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.ПодакцизныйТовар;
|
||
ИначеЕсли ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.ТоварМаркируемыйСИНеИмеющийКМ
|
||
Или ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.ТоварМаркируемыйСИИмеющийКМ Тогда
|
||
Данные.ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.Товар;
|
||
КонецЕсли;
|
||
КонецЕсли;
|
||
|
||
КонецПроцедуры
|
||
|
||
#КонецОбласти
|
||
|
||
|
||
#КонецОбласти |