четверг, 12 марта 2015 г.

1c специалист задача 1.25

Условие из сборника:
Компания занимается оптовой торговлей. Взаиморасчеты с покупателями ведутся  в  разрезе  счетов.  Покупателю  выставляется  счет (документ «Счет»),  на основании  которого  далее  происходит  отгрузка  документами «Расходная накладная»,  причем  накладных  по  одному  счету  может  быть  несколько. Считается,  что  товар  по  счету  в  конце  концов  будет  отгружен  полностью,  а накладные могут быть только на основании счета.  При выставлении счета каждый раз оговаривается срок (количество дней), в  который  покупатель  должен  оплатить  товар,  причем  срок  отсчитывается относительно  даты  полной  отгрузки  товара  по  этому  счету.  В  том  случае,  если товар по счету отгружен полностью, срок оплаты истек, а покупатель оплатил не всю сумму, ему насчитываются пени. Для  расчета  пеней  пользователями  раз  в  неделю  формируется  документ «Пени», в котором автоматически должны рассчитываться пени по формуле:  «количество дней просрочки» * «% пени» * «оставшаяся сумма задолженности по счету».
Просрочка отсчитывается от даты полной отгрузки плюс срок оплаты (из
счета). Процент пеней также указывается в каждом счете. В сумму задолженности
включаются пени. Складской учет товаров не ведется. Можно  считать,  что  документы  задним  числом  не  вводятся,  но существующие документы могут перепроводиться.
При  поступлении  оплаты (документ «Приход  денег»)  в  первую  очередь покрывается  задолженность  по  самым  старым  счетам.  В  документе «Приход денег»  указывается  только  покупатель  и  сумма,  а  распределение  по задолженности должно происходить автоматически при проведении документа. Необходимо построить отчет для анализа состояния счетов на выбранную дату и анализ счета за период.



Решение:

1) Для решения потребуется 2 регистра накопления "Взаиморасчеты" и "Счета".
Структуры регистров:
Взаиморасчеты Измерения "Контрагент", "Счет" ресурс "Сумма".
Счета Измерения "Контрагент",  ресурс "Сумма".

2)  Документы "Расходная накладная " и 3 новых "Пени", "ПоступлениеДенег" и "Счет".
Документы будут делать движения по регистрам след. образом:
Счет ( Счет +)
Расходная накладная (Взаиморасчеты+ , Счета-)
Поступление денег "Взаиморасчеты-)
Пени(Взаиморасчеты+)

3) Документ "Счет"
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.Счета.Записывать = Истина;
Движение = Движения.Счета.ДобавитьПриход();
Движение.Период = Дата;
Движение.Счет = Ссылка;
Движение.Сумма = Сумма;
КонецПроцедуры

4) Документ "Расходная накладная"
Чтобы документ вводился только на основании счета потребуется 2 процедуры

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Если Не ЗначениеЗаполнено(Объект.Счет) Тогда
Отказ = Истина;
КонецЕсли;
КонецПроцедуры

Обработка проведения:

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


5) Документ "Поступление денег"
Процедура ОбработкаПроведения(Отказ, Режим)
Движения.Взаиморасчеты.Записывать = Истина;
Движения.Взаиморасчеты.Записать() ;
// Блокировка
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.Взаиморасчеты");
ЭлементБлокировки.УстановитьЗначение("Контрагент", Контрагент);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Запрос  = Новый("Запрос");
Запрос.Текст = "ВЫБРАТЬ
              | ВзаиморасчетыОстатки.Счет,
              | ВзаиморасчетыОстатки.СуммаОстаток КАК Долг
              |ИЗ
              | РегистрНакопления.Взаиморасчеты.Остатки(&ТочкаИтогов, Контрагент = &Контрагент) КАК ВзаиморасчетыОстатки
              |
              |УПОРЯДОЧИТЬ ПО
              | ВзаиморасчетыОстатки.Счет.Дата
              |ИТОГИ
              | СУММА(Долг)
              |ПО
              | ОБЩИЕ";
Запрос.УстановитьПараметр("Контрагент",Контрагент);
ТочкаИтогов = ?(Режим= РежимПроведенияДокумента.Оперативный, Неопределено, Новый Граница(МоментВремени(),ВидГраницы.Исключая));
Запрос.УстановитьПараметр("ТочкаИтогов",ТочкаИтогов);
ВыборкаИтоги = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,"Общие");
ВыборкаИтоги.Следующий();
Если ВыборкаИтоги.Долг < Сумма Тогда
Отказ = Истина;
Сообщение = Новый("СообщениеПользователю");
Сообщение.Текст = "Сумма документа превышает сумму долга "+ ВыборкаИтоги.Долг;
Сообщение.Сообщить();
Иначе
ОсталосьСписать = Сумма;
Выборка = ВыборкаИтоги.Выбрать();
Пока Выборка.Следующий() и ОсталосьСписать >0 Цикл 
СуммаКСписанию = Мин(ОсталосьСписать, Выборка.Долг);
Движение = Движения.Взаиморасчеты.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Контрагент = Контрагент;
Движение.Счет = Выборка.Счет;
Движение.Сумма = СуммаКСписанию;
ОсталосьСписать = ОсталосьСписать - СуммаКСписанию;
КонецЦикла;
КонецЕсли;
КонецПроцедуры


6) Документ "Пени"

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.Взаиморасчеты.Записывать = Истина;
Движения.Взаиморасчеты.Записать() ;

Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.Взаиморасчеты");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.Счета");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
              | СчетаОстаткиИОбороты.Счет,
              | СчетаОстаткиИОбороты.СуммаКонечныйОстаток,
              | МАКСИМУМ(СчетаОстаткиИОбороты.Регистратор.Дата) КАК ДатаПолнойОтгрузки
              |ПОМЕСТИТЬ Счета
              |ИЗ
              | РегистрНакопления.Счета.ОстаткиИОбороты(, &ТочкаИтогов, Регистратор, , ) КАК СчетаОстаткиИОбороты
              |ГДЕ
              | СчетаОстаткиИОбороты.СуммаКонечныйОстаток = 0
              |
              |СГРУППИРОВАТЬ ПО
              | СчетаОстаткиИОбороты.Счет,
              | СчетаОстаткиИОбороты.СуммаКонечныйОстаток
              |;
              |
              |////////////////////////////////////////////////////////////////////////////////
              |ВЫБРАТЬ
              | Счета.Счет,
              | ЕСТЬNULL(ВзаиморасчетыОстатки.СуммаОстаток, 0) КАК Долг,
              | Счета.Счет.ПроцентПени КАК ПроцентПени,
              | ВзаиморасчетыОстатки.Контрагент,
              | РАЗНОСТЬДАТ(Счета.ДатаПолнойОтгрузки, &Дата, ДЕНЬ) КАК ДнейПросрочки
              |ИЗ
              | РегистрНакопления.Взаиморасчеты.Остатки(
              | &ТочкаИтогов,
              | Счет В
              | (ВЫБРАТЬ
              | Счета.Счет
              | ИЗ
              | Счета)) КАК ВзаиморасчетыОстатки
              | ЛЕВОЕ СОЕДИНЕНИЕ Счета КАК Счета
              | ПО ВзаиморасчетыОстатки.Счет = Счета.Счет";

Запрос.УстановитьПараметр("Дата", Дата);
ТочкаИтогов = ?(РежимПроведения= РежимПроведенияДокумента.Оперативный, Неопределено, Новый Граница(МоментВремени(),ВидГраницы.Исключая));
Запрос.УстановитьПараметр("ТочкаИтогов",ТочкаИтогов);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.Взаиморасчеты.ДобавитьПриход();
Движение.Период     = Дата;
Движение.Счет       = Выборка.Счет;
Движение.Контрагент = Выборка.Контрагент;
Движение.Сумма      = Выборка.Долг * Выборка.ДнейПросрочки *(Выборка.ПроцентПени/100);
КонецЦикла;

КонецПроцедуры

7) Отчет "Анализ состояния счетов"

Текст запроса:

ВЫБРАТЬ
СчетаОстаткиИОбороты.Счет,
МАКСИМУМ(СчетаОстаткиИОбороты.Регистратор.Дата) КАК РегистраторДата
ПОМЕСТИТЬ ОтгруженныеСчета
ИЗ
РегистрНакопления.Счета.ОстаткиИОбороты(, &Период, Регистратор, , ) КАК СчетаОстаткиИОбороты
ГДЕ
СчетаОстаткиИОбороты.СуммаКонечныйОстаток = 0

СГРУППИРОВАТЬ ПО
СчетаОстаткиИОбороты.Счет
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
СчетаОстатки.Счет
ПОМЕСТИТЬ НеотгруженныеСчета
ИЗ
РегистрНакопления.Счета.Остатки(&Период, ) КАК СчетаОстатки
ГДЕ
СчетаОстатки.СуммаОстаток > 0
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВзаиморасчетыОстатки.Счет,
ОтгруженныеСчета.РегистраторДата КАК ДатаПолнойОтгрузки,
ВзаиморасчетыОстатки.СуммаОстаток КАК ЗадолженностьПоСчету
ИЗ
РегистрНакопления.Взаиморасчеты.Остатки(
&Период,
Счет В
(ВЫБРАТЬ
НеотгруженныеСчета.Счет КАК Счет
ИЗ
НеотгруженныеСчета КАК НеотгруженныеСчета)
ИЛИ Счет В
(ВЫБРАТЬ
ОтгруженныеСчета.Счет КАК Счет
ИЗ
ОтгруженныеСчета КАК ОтгруженныеСчета)) КАК ВзаиморасчетыОстатки
ЛЕВОЕ СОЕДИНЕНИЕ ОтгруженныеСчета КАК ОтгруженныеСчета
ПО ВзаиморасчетыОстатки.Счет = ОтгруженныеСчета.Счет
ГДЕ

ВзаиморасчетыОстатки.СуммаОстаток > 0

8) Отчет "Анализ счета за период"

ВЫБРАТЬ
ВзаиморасчетыОстаткиИОбороты.Регистратор КАК Документ,
ВзаиморасчетыОстаткиИОбороты.СуммаПриход КАК Задолженность,
ВзаиморасчетыОстаткиИОбороты.СуммаРасход КАК Оплачено
ИЗ
РегистрНакопления.Взаиморасчеты.ОстаткиИОбороты(&ДатаНачала, &ДатаОкончания, Регистратор, ДвиженияИГраницыПериода, Счет = &Счет) КАК ВзаиморасчетыОстаткиИОбороты

УПОРЯДОЧИТЬ ПО
ВзаиморасчетыОстаткиИОбороты.Регистратор.Дата




Комментариев нет:

Отправить комментарий