Товарная скидка

Скидка дилерская — предоставляется дилерам для покрытия их расходов на продажу и сервисное обслуживание обеспечивает им определённый размер прибыли, который может достигать 30%.  

СКИДКИ ДИЛЕРСКИЕ — см. ДИЛЕРСКИЕ СКИДКИ  
СКИДКА ДИЛЕРСКАЯ — сумма денег, которая покрывает собственные расходы дилера на сервис и продажу и обеспечивает ему обусловленную прибыль.  
Скидка бонусная 596 Скидка дилерская 596 Скидка за платеж наличными 596 Скидка закрытая 596 Скидка количественная 596 Скидка налоговая 596 Скидка оптовая 596 Скидка сезонная 596 Скидка товарообменная 596 Скидка торговая 596 Скидка функциональная 596 Склад /65, /75, 259, 259, 300—301, 331, 366, 481,  
Ставки по краткосрочным коммерческим векселям несколько выше, чем по казначейским векселям с тем же сроком погашения, и примерно такие же, как ставки по банковским акцептам. Векселя, продаваемые непосредственно инвесторам, обычно обладают менее высокой доходностью, чем распространяемые через дилерскую сеть. Краткосрочные коммерческие векселя продаются в основном со скидкой, а срок погашения варьируется, как правило, от 30 до 270 дней. Большинство владельцев векселей держат их вплоть до срока погашения, так как эти бумаги фактически не имеют вторичного рынка. Продавцы, реализующие краткосрочные коммерческие векселя напрямую, выкупают их по требованию. Также могут быть сделаны распоряжения о выкупе векселей через сеть дилеров, которые занимались их распространением. Краткосрочные коммерческие векселя имеют достаточно высокие номиналы, по меньшей мере 100 000 дол.  
Дилерская скидка предоставляется производителями своим постоянным представителям или посредникам по сбыту, в том числе и заграничным. Эти скидки широко распространены при продаже автомобилей, тракторов, некоторых видов стандартного оборудования. Дилерские скидки на автомобили колеблются в зависимости от марки машины и составляют в среднем 15-20% розничной цены.  
Дилерские скидки (наценки) уменьшаются, но их влияние на взаимоотношения производителя со своими дилерами увеличивается.  
Некоторые виды инструментов денежного рынка находятся в обращении и являются предметом торговли на активном дилерском рынке, чего нельзя сказать о других. Одни могут быть приобретены любым лицом, имеющим для этого средства, другие -только учреждениями определенной категории. Многие инструменты денежного рынка продаются со скидкой (дисконтом), например, 90-дневная бумага с номиналом 100 000 продается за 98 000, при ее погашении инвестору будет выплачена номинальная стоимость и его доход составит при этом 2000.  
К цене товара в контракте могут быть предусмотрены скидки за оборот, за срочность платежа, дилерские.  
Генеральным дилером по отношению к подавляющей части заводов-изготовителей машин в стране является ОАО «Росагроснаб», которое заключает с ними генеральные договоры на поставку машин, в которых предусмотрены все принципиальные вопросы организации и финансирования поставок порядок и сроки поставок, в частности на реализацию машин со сроком оплаты до трех месяцев (консигнация), уровень цен на продукцию, скидки с цены до 20 % в зависимости от фактических сроков реализации, обеспечение гарантийным комплектом запасных частей, нормативно-технической документацией, ответственность завода за качество продукции и др. Генеральные дилерские договоры закладывают основу для восстановления ответственности заводов-изготовителей за качество и комплектность выпускаемой ими техники, ее дилерское обслуживание .  

Дилерская служба в России, как и за рубежом, должна нести ответственность за предпродажное и послепродажное обслуживание реализуемых машин до истечения гарантийного срока их эксплуатации, а также за обеспечение запасными частями до конца срока службы. Это определяется перечнем обязанностей дилера, которые оплачиваются ему фирмой-изготовителем при предоставлении торговой скидки с цены реализуемых машин и запасных частей.  
Коммерческие ценные бумаги представляют собой краткосрочные долговые обязательства корпораций со сроком обращения от 30 до 270 дней. Это необеспеченный простой вексель, выпускаемый со скидкой с номинала. Размещаются данные ценные бумаги либо самими эмитентами, либо через крупные дилерские фирмы.  
Автопарк Количество моделей Дилерская сеть Скидки с объема Нет Нет Нет  
Поставщики-экспортеры предоставляют своим постоянным посредникам дилерские скидки при продаже автомобилей, тракторов, оборудования в среднем в объеме 15— 20% розничной цены.  
ОПТОВАЯ ТОРГОВЛЯ — торговля крупными партиями товаров продажа товаров оптовым покупателям, потребляющим их в значительном количестве или продающим их затем в розницу. Оптовая торговля осуществляется через сеть оптовых и мелкооптовых покупателей-посредников (дилеров) по ценам, предусматривающим дилерские скидки и отличающимся от розничных в сторону уменьшения. Среди торговых компаний определенное их число занимается только оптовой торговлей.  
ДИЛЕРСКИЕ СКИДКИ — предоставляются оптовым и розничным торговцам, агентам и посредникам. Эти скидки необходимы для покрытия расходов дилеров на продажу и сервис и обеспечения им определенного размера прибыли. В ценовой политике встречается метод «вертикального ценообразования», по которому предприятие-изготовитель само устанавливает розничную цену, за-  
ДИЛЕРСКИЕ СКИДКИ -сумма денег, покрывающая собственные расходы дилера на продажу и сервис, а также обеспечивающая ему обусловленную прибыль.  
В зависимости от места продавца в системе товародвижения различают функциональную скидку и дилерскую скидку. Фактически они представляют собой распределение выручки от продажи товара между отдельными звеньями в цепочке товародвижения. Их применяют производители, контролирующие цены конечных продаж. Величина скидки должна быть достаточной, чтобы возместить расходы продавца и обеспечить ему в данной сфере деятельности получение традиционной прибыли.  
Дилерские скидки предоставляются производителем постоянным агентам сбыта. Эти скидки широко применяются при продаже автомобилей. Дилерские скидки на автомобили колеблются в зависимости от марки машины в пределах 15-20% от розничной цены.  
ЦЕНОВЫЕ СКИДКИ (rebates) — метод уторговывания цены с учетом состояния рынка и условий контракта. Широко распространен в международной торговле. Цены, первоначально объявляемые поставщиками в прейскурантах, носят справочный характер и, как правило, подлежат корректировке в ходе переговоров с покупателем. По оценкам специалистов существует около 40 видов Ц.с. Наиболее распространенными являются следующие виды скидок 1. бонусные скидки (предоставляются крупным оптовым покупателям, как правило, постоянным клиентам, не за каждую отдельную сделку, а за обусловленный объем оборота в год достигают 7-8% стоимости оборота) 2. временные скидки применяются главным образом в торговле продукцией массового спроса, имеющей сезонный характер) 3. дилерские скидки (предоставляются оптовым и розничным торговцам, агентам и посредникам эти скидки должны покрывать расходы дилеров на продажу и сервис и обеспечивать им определенный размер прибыли в ценовой политике часто встречается метод «вертикального ценообразования», по которому предприятие-изготовитель само устанавливает розничную цену, заранее закладывая в нее размеры скидок оптовым и розничным торговцам величина дилерской скидки зависит от вида товара и объема посреднических услуги достигает 30%) 4. закрытые скидки (предоставляются на продукцию, обращающуюся в замкнутых экономических единицах, например, во внутрифирменных поставках или во внутренней торговле международных замкнутых группировок на товары, поставляемые по специальным межправительственным соглашениям) 5. количественные скидки (размер их меняется в зависимости от величины или серийности заказа при поставках товаров массового спроса размер их относительно невелик, а для товаров, производимых малыми сериями или по индивидуальным заказам, скидка нз хол»исство имеет большое значение, поскольку увеличение серии ведет к сокращению издержек производства по отдельным контрактам скидки на количество составляют до 15%) 6. скидки «сконто» (предоставляются за оплату наличными или за досрочное осуществление платежей по сравнению с контрактом могут составлять 3-5% стоимости сделки) 7. специальные скидки (предоставляются покупателям, с которыми фир-  
Дилерские скидки (dealer dis ount) предоставляются производителями своим постоянным представителям или посредникам по сбыту, в том числе и заграничным. Эти скидки  
Аналогично определяется цена, по которой дилер продает такой вексель. Он предлагает инвесторам купить его со скидкой 2,397% . Это означает, что он готов продать вексель за 9760,30 . Разница цен покупки и продажи, составляющая в данном примере 9,60 ( 9760,30 — 9750,70), получила название дилерского диапазона, или спреда (dealer s spread). Спред является своего рода компенсацией за поддержание дилером запаса векселей и связанный с этим риск, а также за понесенные издержки.  
Другими словами, в первых четырех публикациях расставляются «заманушки» (скидки, льготы, отсрочка платежа и т.д.) для всех. Начиная с шестой публикации, «заманушки» для всех остаются только в тех регионах, где представители (дистрибьюторы) еще не сформировали работающую дилерскую сеть. А там, где вертикаль «производство — розница» уже работает, остаются только эксклюзивные, адресные скидки и льготы.  
В конкурирующей фирме Консультант-плюс (http www. onsultant.ru) идею интеграции оценили как хорошую, но ограниченную и не несущую новых потребительских качеств. Ведь в многозадачной среде Windows осуществить вызовы нужных информационных блоков из двух неинтегрированных систем (бухгалтерской и правовой) можно так же быстро и просто, как и из одной интегрированной. Консультант-плюс решил использовать другую козырную карту партнерства — создать определенный стимул к энергичной работе у поставщиков и дилеров. Минуя разработчиков бухгалтерских программ, Консультант-плюс стал напрямую выходить сразу на их дилеров с существенными, почти в полцены, скидками. Это были скидки не потребителю, а дилеру. Выход на чужих дилеров, в обход разработчиков (по существу, акция частичного захвата чужой дилерской сети) оказался шагом не только, безусловно, сильным, но и неожиданным для конкурентов. Он понадобился, чтобы экстренно помешать конкуренту, понижающему цену, захватить дополнительную долю рынка.  
Дилерская скидка (англ, dealer dis ount) предоставляется производителями своим постоянным представителям или посредникам по сбыту, в том числе и иностранным. Эти скидки широко распространены при продаже автомобилей, тракторов и различных видов стандартного оборудования и пр.  

Вот еще один вопрос по которому наблюдаю кашу и в головах и в прайс-листах компаний.
Как выгладит эта каша? Приведу невымышленый диалог. По-моему очень узнаваемо, не правда ли?

Диалог селса и нач. отдела продаж:

В порыве показать профессионализм, и понимая бессмысленость диалога, многие из нас сразу же бросятся коментировать: непонятно что такое 1%, за что, что значит «брать больше»? И мы будем с Вами конечно же правы. Давайте же разберемся, за что нужно «давать» и сколько «давать».

Классификация скидок

Скидка может быть одного из трех видов:

  • маркетинговая скидка;
  • сбытовые скидки;
  • логистические скидки.

К маркетинговым скидкам относят скидки напрямую не связанные с текущей и отлаженой логистикой продаж: товар — в обмен на деньги. Данные скидки влияют на перспективы развития, стимулируют взаимоотношения партнеров (CRM), структурированность сбытового канала.

К сбытовым скидкам относят скидки напрямую связанные с текущими сделками, по обеспечению заданой рентабильности продаж и текущей плановой оборачиваемости складских запасов заключенным (заключаемым) сделкам.

К логистическим скидкам относят скидки для оптимизацией денежных, товарных потоков, влияющих на текущие финансовые показатели деятельности компании.

Маркетинговые скидки

Скрытая рекламная скидка

К такого рода скидкам можно отнести организацию фирмой-производителем рекламы своей продукции с указанием списка торговых фирм, которые этой продукцией торгуют. Тем самым фирма-производитель реально экономит средства своих дилеров на рекламу своих торговых названий, что по экономической природе равнозначно предоставлению им дополнительной скидки.

Функциональная скидка (скидка под дистрибуцию)

Производитель предоставляет различные функциональные скидки игрокам торгового канала, оказывающим ему разные виды услуг (логистические, услуги по развитию сети продаж, построению дилерской сети). Функциональная скидка в словаре маркетолога

Дилерская скидка(dealer discount)

Предоставляется производителем своим постоянным представителям или посредникам по сбыту (например: партнерская программа по обслуживанию покупателей в сети магазинов: акции, использование залов для промо, мерчандайзинг и т.п. стимулируется дилерской скидкой).

Скидки с учетом межкультурных коммуникаций

В практической деятельности маркетинг сталкивается с весьма важным обстоятельством, которое следует отнести к так называемым культурным различиям, что также является предметом маркетинговых исследований.
В среднеазиатских, арабских, некоторых балканских странах и отдельных закавказских республиках, в ходе торговых переговоров считается делом чести достичь большой скидки с цены предложения. И хотя это обстоятельство связано с комплексом восточной ментальности, многие импортеры не подпишут договор, который не содержит позицию о скидках, превышающих в целом 20 – 30% от предложенной цены. Поскольку этот факт известен в маркетинговой и торговой среде, то некоторые компании считают необходимым предварительно искусственно завысить цены на ожидаемый процент, а в дальнейшем представить его оговоренной в контракте скидкой.

Сервисные скидки

Значительная часть промышленной продукции нуждается в техническом обслуживании в период эксплуатации. Созданию и поддержанию эффективной сервисной сети, которая требует значительных инвестиций и усилий, предпочитают предоставление сервисной скидки. Этот подход к решению проблемы был бы приемлем, если бы имелась возможность контроля за осуществлением реципиентом дополнительных функций и способ оценки эффективности такой скидки.

  • со стороны покупателя — величиной затрат на хранение заблаговременного приобретенного товара до начала сезона его продаж (включая плату за привлеченные для этого кредиты);
  • со стороны производителя — величиной затрат и потерь, которые ему пришлось бы понести в случае, если бы изготовленный товар хранился до начала сезона на его собственных складах, а производство было либо остановлено из-за омертвления оборотного капитала в запасах готовой продукции, либо поддерживалось за счет дополнительно привлеченных кредитов под пополнение оборотного капитала.

Следовательно, величина скидок должна обеспечивать покупателю экономию большую, чем прирост его затрат на хранение товара до периода сезонного подъема спроса. С другой стороны, производитель может предоставить такие скидки — на сумму не большую, чем величина его потерь из-за замедления оборачиваемости капитала в результате хранения товара до начала сезона на собственных складах и неполучения выручки от продаж.
Логика скидок на внесезонную закупку требует их дифференциации во времени: чем ранее до начала сезона приобретается товар, тем больше должна быть величина скидки.

Скидки для поощрения продаж нового товара.

Такие скидки можно рассматривать как дополнение к плановым скидкам, которые содействуют продвижению на рынок нового товара. Как правило, таких скидок в форме финансирования национальной рекламной кампании с указанием названий торговых фирм, продающих данный товар, оказывается недостаточно. Например, такая реклама реально не дает покупателям информации о том, где они фактически могут купить упомянутый товар в своем городе (районе).

Поэтому дилерам и конечным продавцам приходится проводить собственные рекламные кампании, используя местные органы массовой информации (расценки за рекламу в которых обычно к тому же ниже, чем в общенациональной прессе или по национальному телевидению). Это дает им возможность указывать в такой рекламе адреса своих магазинов, что реально обеспечивает прирост продаж.

Однако такая реклама все же требует немалых средств. Средством их компенсации местным продавцам и являются скидки для поощрения продаж.

Скидка для поощрения продаж – мера снижения стандартной цены продажи, которая гарантируется торговым посредникам, если они берут для реализации новые товары, продвижение которых на рынок требует повышенных расходов на рекламу и услуги торговых агентов.

Сбытовые скидки

Скидка за оборот, бонусная скидка(bonus)

Скидка предоставляется постоянным покупателям на основании специальной доверенности. В контракте в этом случае устанавливается шкала скидок (scale of discount), в зависимости от достигнутого оборота в течение определенного срока (обычно одного года), а также порядок выплаты сумм на основе этих скидок.

Такую систему скидок оформляют в виде колонок прайс-листа. Вот это — прайс-лист.Я именую (ну вот нравится так) колонки цен — протоколами цен: 1й протокол, 2й протакол. Отчего так? Согласование и протоколирование цен — правовая основа сделок, зафиксированная в ГК РФ. Если где-либо в других статьях наткнетесь на «протоколы цен» — это от этого.

Логистические скидки

Остальные типы скидок можно отнести к категории тактических логистических.
Их объединяет экономический источник — прибыль(!), а также общая задача — создание дополнительных стимулов для покупателя совершить покупку. Использованиелогистических скидок ведет к снижению реальной цены приобретения товара и соответственно к увеличению премии покупателя. Эта премия представляет собой разницу между экономической ценностью товара для покупателя и ценой, по которой этот товар ему удалось купить.
К основным видам скидок относится:

Скидка за объем покупаемого товара

Cоразмерное уменьшение цены для покупателей, закупающих большие количества одного вида товара. Обычно скидка устанавливается в процентах к общей стоимости или единичной цене установленного объема поставки, например, 10% скидки при заказе свыше 1000 штук. Скидки могут предлагаться на некумулятивной основе (на каждый размещенный заказ) или на кумулятивной основе (на количество изделий, заказанных за определенный период).
Скидки за количество должны предлагаться всем покупателям, но в этом случаепоставщик/продавец должен следить за тем, чтобы сумма скидок не превышала его суммы экономии по издержкам в связи с увеличением объемов продаваемого товара. Эта экономия может складываться за счет сокращения издержек по продаже (торговой обработке), складированию, поддержанию товарного запаса и транспортировке товара. Скидки такого рода могут служить также для потребителя стимулом делать закупки у одного продавца (постоянные покупки).

Скидка за платеж наличными

Если это Вам необходимо, уменьшение цены для покупателей, которые оперативно оплачивают счета наличными средствами. Покупатель, расплатившийся в течение 10 дней, получает, например, двух-, трехпроцентное снижение от суммы платежа. Эта скидка может применяться и частично, например, только для процента от всей суммы, полученной в пределах 30 дней. При более крупном объеме поставки или более дорогом оборудовании данный вид скидки может сильно активизировать местного контрагента, заинтересованного быстрее продать и получить свой немалый доход.
Подобные скидки широко применяются для улучшения состояния ликвидности поставщика/продавца, ритмичности его денежных поступлений и сокращения расходов в связи с взысканием дебиторской задолженности.

Скидка за отказ от дебиторки (за сокращение сроков дебиторской задолженности)

Скидкой также можно стимулировать сокращение сроков товарного кредита, предоставляемого поставщиком — клиенту.

Прогрессивная скидка (progressive discount)

Скидка за количество или серийность предоставляется покупателю при условии покупки им заранее определенного и увеличивающегося в количестве товара. Серийные заказы представляют интерес для производителей, так как при изготовлении однотипного товара снижаются издержки производства. Скидка дается по факту, или авансово, под договор, фиксирующий такую прогрессию. Часто селс дает такую скидку и без договора, по устной договоренности. Вот такие договоренности нужно в любом случае фиксировать, хотя бы внутри фирмы в CRM системе.

Экспортные скидки (export rebate)

Предоставляются продавцами при продаже товаров иностранным покупателям сверх тех скидок, которые действуют для покупателей внутреннего рынка. Их цель – повысить конкурентоспособность товара на внешнем рынке.

Скидка за ускорение оплаты.

Главная задача скидок за ускорение оплаты — сокращение сроков погашения дебиторской задолженности и ускорение оборачиваемости оборотного капитала фирмы. Поэтому этот коммерческий инструмент можно в большей мере отнести к сфере менеджмента, чем собственно ценообразования. Но поскольку такие скидки устанавливаются по отношению к ценам, то традиционно их определением занимаются ценовики вместе с финансистами и бухгалтерами.
Скидка за ускорение оплаты – мера снижения стандартной продажной цены, которая гарантируется покупателю, если он произведет оплату приобретенной партии товара ранее установленного контрактом срока.
Схема скидки за ускорение оплаты включает три элемента:

  • собственно количественную величину скидки;
  • срок, в течение которого покупатель имеет возможность воспользоваться такой скидкой;
  • срок, в течение которого должна быть произведена оплата всей суммы задолженности за поставленную партию товара, если покупатель не воспользуется правом на получение скидки за ускоренную оплату.

Величина ставки за ускорение платежа обычно определяется двумя факторами:

  • уровнем таких ставок, традиционно сложившимся на данном рынке;
  • уровнем банковских процентных ставок за кредиты под пополнение оборотных средств.

Связь скидки за ускорение оплаты с ценой кредитных ресурсов вполне логична. Если производитель не может добиться ускорения погашения дебиторской задолженности, то ему приходится пополнять свои оборотные средства преимущественно именно за счет кредита. Ускорение оплаты отгруженных товаров сокращает потребность в привлечении средств и обеспечивает экономию за счет уменьшения суммы процентных платежей.

Вместе с тем обычно уровень скидки за ускорение платежа существенно выше, чем цена кредитных ресурсов.

Такое превышение уровня скидки над ценой кредитов оправдывается большим положительным эффектом, который ускоренная оплата оказывает на финансовое состояние фирмы-продавца. Этот эффект возникает в силу того, что досрочные платежи:

  • ускоряют поступление денежных средств на счет продавца и улучшают структуру его баланса, что существенно для получения им самим кредитов, а также влияет на оценку позиции фирмы инвесторами (в том числе на курс ее акций на биржах);
  • уменьшают кредитные риски, связанные с дебиторской задолженностью, и повышают надежность финансового планирования;
  • сокращают затраты фирмы на организацию сбора. дебиторской задолженности.

Скидка за внесезонную покупку

Эта мера снижения стандартной продажной цены, которая гарантируется покупателю, если он приобретет товары сезонного спроса вне периода года, для которого они предназначены. Цель использования скидок за внесезонную закупку состоит в том, чтобы побудить покупателей приобрести эти товары до начала очередного сезона, в самом его начале, либо вообще вне сезона. Это обеспечивает ускорение оборачиваемости активов и позволяет изготовителям сезонных товаров снижать сезонные колебания загрузки своих производственных мощностей.
При хорошо налаженной системе сезонных скидок производители получают возможность организовать и завершить производство товаров для очередного сезона задолго до его начала и своевременно начать подготовку к изготовлению продукции для следующего сезона.
Величина сезонных скидок обычно бывает довольно небольшой и определяется:

Скидки при комплексной закупке товаров.

Многие фирмы, продающие линейки взаимодополняющих товаров, используют особый тип скидок для поощрения покупателей к приобретению нескольких товаров из такой линейки, т. е. к комплексной закупке.
Скидка при комплексной закупке товаров – мера снижения стандартной продажной цены, которая гарантируется покупателю, если он приобретет данный товар вместе с другими дополняющими товарами этой фирмы.
Логика такой скидки состоит в том, что цена каждого из товаров в составе набора оказывается ниже, чем при изолированной покупке, пусть даже в той же самой фирме.

Скидки за возврат ранее купленного товара у данной фирмы (trade-in)

Скидки предоставляются покупателю при возврате им ранее купленного у данной фирмы товара устаревшей модели. Такие скидки применяются при продаже автомобилей, электрооборудования, подвижного состава, стандартного промышленного оборудования и т. п.

Скидки при продаже оборудования, бывшего в употреблении (дефектного).

В разных странах имеются возможности выгодно приобрести бывшие в употреблении машины, механизмы и иное оборудование. Если к тому же и обслуживание хорошо организовано, тотакое приобретение – разумная альтернатива покупке нового оборудования. На не новом оборудовании можно долго работать, при этом эксплуатационные расходы невелики.

Зачеты

Под зачетами понимают другие виды скидок с прейскурантной цены. Например, товарообменный зачет – это уменьшение цены нового товара при условии сдачи старого. Товарообменный зачет наиболее часто применяется при продаже автомобилей и некоторых товаров длительного пользования. Под зачетами на стимулирование сбыта понимают выплаты или скидки с цены для вознаграждения дилеров за участие в программах рекламы и поддержания сбыта.

Кто отвечает за скидки

Точнее это раздел стоило бы назвать: «Кто дает скидки?». Впрочем, пытливому продажнику и так все понятно:

  • за маркетинговые скидки отвечате департамент маркетинга, руководствующийся маркетинговой политикой;
  • за сбытовые скидки несет ответственность отдел продаж, руководстующийся нормами рентабельности продаж и оборачиваемости складских запасов.
  • за логистическими — паритенто департамент товарной логистики, отдел закупок, финансовый департамент, действующий в соответствии с финансовой политикой фирмы.

Поставщики часто предоставляют покупателям различные скидки: торговые, денежные, финансовые, товарные в виде бонусного товара. Так, поставщик в счете-фактуре после подведения итога – 69 997 755 сум. – отдельной строкой указал «Товарная скидка», а ниже – ассортимент лекарств, переданных в качестве товарной скидки на 2 553 972 сум. Далее – «Всего отпущено» на 72 551 127 сум. и завершается строкой «Всего к оплате» – 69 997 755 сум.

В другом случае поставщик после подведения итога в размере 12 080 000 сум. отдельной строкой накладной указал «Финансовая скидка 14%» в размере 1 691 200 сум. «Всего к оплате» – 10 388 800 сум.

Чем различаются эти скидки и которую из них в форме налоговой отчетности по ЕНП по оптовой торговле следует включать в «Прочие доходы, полученные в виде скидки от поставщиков», а которую в «Безвозмездно полученное имущество, имущественные права, а также работы и услуги»?

Как отражать в бухгалтерском учете и налоговой отчетности по ЕНП торговые, денежные, бонусные скидки, полученные от поставщиков?

Н.Наимов,

бухгалтер.

Мы, PHP-разработчики, горды тем, что пишем на ООП-языке (можно легко здесь заменить PHP на C#, Java или другой ООП-язык). Каждая вакансия содержит требования про знание ООП. В каждом собеседовании спрашивают что-нибудь про SOLID или трех «китов» ООП. Но когда дело доходит до дела — мы получаем просто классы, наполненные процедурами. ООП проявляется редко, обычно в коде библиотек.

Обычное веб-приложение — это классы ORM-сущностей, которые содержат данные из строки в базе данных и контроллеры(или сервисы — неважно), содержащие процедуры работы с этими данными. Объектно-ориентированное программирование — оно про объекты, которые владеют собственными данными, а не предоставляют их для обработки другому коду. Отличная иллюстрация этого — вопрос, который был задан в одном чате: «Как я могу улучшить этот код?»

private function getWorkingTimeIntervals(CarbonPeriod $businessDaysPeriod, array $timeRanges): array { $workingTimeIntervals = ; foreach ($businessDaysPeriod as $date) { foreach ($timeRanges as $time) { $workingTimeIntervals = ), ‘end’ => Carbon::create($date->format(‘Y-m-d’) . ‘ ‘ . $time) ]; } } return $workingTimeIntervals; } /** * Удалить события из расписания * * @param array $workingTimeIntervals * @param array $events * @return array */ private function removeEventsFromWorkingTime(array $workingTimeIntervals, array $events): array { foreach ($workingTimeIntervals as $n => &$interval) { foreach ($events as $event) { $period = CarbonPeriod::create($interval, $interval); if ($period->overlaps($event, $event)) { if ($interval <= $event && $interval <= $event) { $interval = $event; } elseif ($interval >= $event && $interval >= $event) { $interval = $event; } elseif ($interval <= $event && $interval >= $event) { $interval = $event; $interval = $event; } else { unset($workingTimeIntervals); } } } } return $workingTimeIntervals; }

Этот код работает с временными интервалами. Метод удаляет множество одних интервалов(событий) из множества других(расписания), чтобы получить свободное время в расписании. Как видите, вся работа здесь вертится вокруг структуры из двух дат. И стиль работы с данными весьма распространённый — некая структура данных(здесь массив) и некий сторонний код, который с ней работает. Организуя код так, легко дублировать его, когда схожая логика понадобится в другом месте. Давайте попробуем сконцентрировать данные и код, с ними работающий, в одном месте.

Каждый раз начиная рефакторинг я проверяю наличие unit-тестов для данного кода. Рефакторинг без тестов может быть весьма болезненным. Код из примера их не имеет и его структура не даёт возможности быстро их написать (методы приватные). Поэтому будем аккуратно проверять логику после рефакторинга.

class Interval { // Типизированные поля из PHP 7.4 public DateTimeImmutable $start; public DateTimeImmutable $end; }

Класс DateTimeImmutable был использован как более удобная альтернатива для работы с датами.

Первое требование к этому классу — начальная дата не должна быть больше конечной.
Намного удобнее когда объект, не удовлетворяющий требованиям, даже не может быть создан, поэтому конструктор — лучшее место для этой проверки.

Я почти всегда начинаю описывать требования к классу через unit-тесты. Позже будет понятно почему. Начнем с обычного конструктора:

class Interval { public DateTimeImmutable $start; public DateTimeImmutable $end; public function __construct(DateTimeImmutable $start, DateTimeImmutable $end) { $this->start = $start; $this->end = $end; } }

Теперь PHPUnit-тесты для нашего требования:

use App\Interval; use PHPUnit\Framework\TestCase; class IntervalTest extends TestCase { private DateTimeImmutable $today; private DateTimeImmutable $yesterday; private DateTimeImmutable $tomorrow; protected function setUp(): void { $this->today = new DateTimeImmutable(); $this->yesterday = $this->today->add(\DateInterval::createFromDateString(«-1 day»)); $this->tomorrow = $this->today->add(\DateInterval::createFromDateString(«1 day»)); parent::setUp(); } public function testValidDates() { $interval = new Interval($this->yesterday, $this->today); $this->assertEquals($this->yesterday, $interval->start); $this->assertEquals($this->today, $interval->end); } public function testInvalidDates() { $this->expectException(\InvalidArgumentException::class); new Interval($this->today, $this->yesterday); } }

Объекты дат для сегодняшнего, вчерашнего и завтрашнего дня помогут читабельности тестов. Первый тест, testValidDates, просто проверяет обычное создание интервала. Второй, testInvalidDates, пытается создать неправильный интервал и ожидает эксепшен. Первый тест пройдет нормально, второй свалится с ошибкой:

Failed asserting that exception of type «InvalidArgumentException» is thrown.

Теперь реализуем эту проверку:

class Interval { public DateTimeImmutable $start; public DateTimeImmutable $end; public function __construct(DateTimeImmutable $start, DateTimeImmutable $end) { if ($start > $end) { throw new \InvalidArgumentException(«Invalid date interval»); } $this->start = $start; $this->end = $end; } }

Теперь оба тесты будут зелеными. Спасибо современной системе типов в PHP, мы не обязаны проверять null и другие значения. Это сильно сокращает объем тестов. Однако, каждый раз, когда разработчик пишет тесты он обязан проверить краевые значения. Очевидным краевым значением для объекта Interval будут одинаковые даты начала и конца. Возможно такое или нет? Вот как unit-тесты помогают создавать хороший дизайн. Они задают хорошие вопросы еще до того, как мы написали настоящий код. До того как разработчик сам задаст их себе. Давайте решим, что пустые интервалы возможны, но добавим новый метод isEmpty к этому классу.

class Interval { public DateTimeImmutable $start; public DateTimeImmutable $end; public function __construct(DateTimeImmutable $start, DateTimeImmutable $end) { if ($start > $end) { throw new \InvalidArgumentException(«Invalid date interval»); } $this->start = $start; $this->end = $end; } public function isEmpty(): bool { return $this->start->getTimestamp() == $this->end->getTimestamp(); } } class IntervalTest extends TestCase { //… public function testNonEmpty() { $interval = new Interval($this->yesterday, $this->today); $this->assertFalse($interval->isEmpty()); } public function testEmpty() { $interval = new Interval($this->today, $this->today); $this->assertTrue($interval->isEmpty()); } }

Мы построили базовый класс для интервала дат. Он может быть использован вместо массивов , но большого смысла в этом нет. Давайте добавим знания об интервале дат в этот объект! Начальное задание было о создании списка свободных интервалов, на основе расписания и занятых слотов. Первый метод создавал интервалы, например:

какой-то день 08:00 — 12:00 какой-то день 13:00 — 17:00 следующий день 08:00 — 12:00 следующий день 13:00 — 17:00 …

Второй метод удалял занятые слоты из расписания, оставляя лишь свободные:

Занятые слоты: какой-то день 08:00 — 09:00 какой-то день 16:00 — 17:00 следующий день 13:00 — 17:00 Результат: какой-то день 09:00 — 12:00 какой-то день 13:00 — 16:00 следующий день 08:00 — 12:00 …

Я хочу переместить эту логику в класс Interval:

$period = CarbonPeriod::create($interval, $interval); if ($period->overlaps($event, $event)) { if ($interval <= $event && $interval <= $event) { $interval = $event; } elseif ($interval >= $event && $interval >= $event) { $interval = $event; } elseif ($interval <= $event && $interval >= $event) { $interval = $event; $interval = $event; } else { unset($workingTimeIntervals); } }

Новый метод класса Interval: remove(Interval $other) будет изменять объект, удаляя из него переданный интервал. Код станет намного чище:

private function removeEventsFromWorkingTime($workingTimeIntervals, $events): array { foreach ($workingTimeIntervals as $n => $interval) { foreach ($events as $event) { $interval->remove($event); if ($interval->isEmpty()) { unset($workingTimeIntervals); } } } return $workingTimeIntervals; }

Отлично. Время реализовать новый метод. И начнём, очевидно, с тестов! Когда разработчик начинает разрабатывать с тестов, он обязан подумать о требованиях к классу и методам и подумать хорошо. Это полезно. Проанализируем требования, рассмотрев возможные случаи.

Интервал не должен быть изменён, если $other не касается его.

class IntervalRemoveTest extends TestCase { private DateTimeImmutable $minus10Days; private DateTimeImmutable $today; private DateTimeImmutable $yesterday; private DateTimeImmutable $tomorrow; private DateTimeImmutable $plus10Days; protected function setUp(): void { $this->today = new DateTimeImmutable(); $this->yesterday = $this->today->sub(\DateInterval::createFromDateString(«1 day»)); $this->tomorrow = $this->today->add(\DateInterval::createFromDateString(«1 day»)); $this->minus10Days = $this->today->sub(\DateInterval::createFromDateString(«10 day»)); $this->plus10Days = $this->today->add(\DateInterval::createFromDateString(«10 day»)); parent::setUp(); } public function testDifferent() { $interval = new Interval($this->minus10Days, $this->yesterday); $interval->remove(new Interval($this->tomorrow, $this->plus10Days)); $this->assertEquals($this->minus10Days, $interval->start); $this->assertEquals($this->yesterday, $interval->end); } }

Интервал, полностью покрытый переданным интервалом, должен стать пустым.

class IntervalRemoveTest extends TestCase { public function testFullyCovered() { $interval = new Interval($this->yesterday, $this->tomorrow); $interval->remove(new Interval($this->minus10Days, $this->plus10Days)); $this->assertTrue($interval->isEmpty()); } public function testFullyCoveredWithCommonStart() { $interval = new Interval($this->yesterday, $this->tomorrow); $interval->remove(new Interval($this->yesterday, $this->plus10Days)); $this->assertTrue($interval->isEmpty()); } // and testFullyCoveredWithCommonEnd() }

Следующий случай, когда переданный интервал частично перекрывает текущий:

Что если переданный интервал располагается внутри текущего?

Эмммм?! Наш интервал разделился на два! Весь дизайн нашего метода remove оказался неверным! Кстати, и изначальный код тоже содержит ошибку в этом месте:

} elseif ($interval <= $event && $interval >= $event) { $interval = $event; $interval = $event;

Но обнаружена она будет сильно позже и хорошо если не пользователями приложения.

Мы даже не начали писать сам код, но уже нашли большую проблему в дизайне. Да, этот пример весьма прост и многие разработчики нашли бы проблему и без тестов, но для более сложных случаев найти проблему обычными умозаключениями будет весьма непросто. Вот почему тесты полезны. Они помогают писать код, часто избегая серьезных просчетов в дизайне. Некоторые разработчики говорят, что не любят писать тесты, потому что с ними код пишется медленней. Для простых тестов, вроде тех, которые мы написали вначале, это верно. Но для ситуаций посложнее, код с тестами часто написать бывает быстрее, чем без них! Тесты задают хорошие и весьма точные вопросы про дизайн вашего кода. Разработчик обязан создавать хороший дизайн.

Одним из возможных решений является создание нового класса — IntervalCollection, представляющего собой множество интервалов и операции над ними:

class Interval { public DateTimeImmutable $start; public DateTimeImmutable $end; public function __construct(DateTimeImmutable $start, DateTimeImmutable $end) { if ($start > $end) { throw new \InvalidArgumentException( «Invalid date interval»); } $this->start = $start; $this->end = $end; } public function isEmpty(): bool { return $this->start === $this->end; } /** * @param Interval $other * @return Interval */ public function remove(Interval $other) { if ($this->start >= $other->end || $this->end <= $other->start) return ; if ($this->start >= $other->start && $this->end <= $other->end) return ; if ($this->start < $other->start && $this->end > $other->end) return ; if ($this->start === $other->start) { return ; } return ; } } /** @mixin Interval */ class IntervalCollection extends \ArrayIterator { public function diff(IntervalCollection $other) : IntervalCollection { /** @var Interval $items */ $items = $this->getArrayCopy(); foreach ($other as $interval) { $newItems = ; foreach ($items as $ourInterval) { array_push($newItems, …$ourInterval->remove($interval)); } $items = $newItems; } return new self($items); } }

Класс IntervalCollection — это другой пример концентрации логики рядом с данными, которыми она оперирует. Не просто массив с объектами Interval, который обрабатывается некоторыми сторонними функциями, а целый класс с правильным именем и покрытый тестами.

Полный исходный код с тестами можно найти здесь — https://github.com/adelf/intervals-example. Текущее решение не очень оптимальное с точки зрения производительности, но логика его спрятана в методе IntervalCollection::diff и хорошо покрыта тестами. Если другой разработчик захочет оптимизировать его, он сможет это сделать без всякого страха. Любую ошибку в логике тесты поймают немедленно. Это второе преимущество unit-тестов.

Организация вашего кода объектами, которые по-настоящему владеют своими собственными данными помогают сильно уменьшить coupling (связанность или зацепление), что очень важно в больших проектах. Следующим этапом концентрации данных и кода будет переделка модификаторов доступа полей на private: