Настройка акций в Кассире — различия между версиями
Материал из wiki.standart-n.ru
Aleksnick (обсуждение | вклад) |
Agk (обсуждение | вклад) (→Примеры акций) |
||
| (не показаны 22 промежуточные версии 4 участников) | |||
| Строка 1: | Строка 1: | ||
| − | = | + | =Настройка ТМС Акции в кассире= |
| − | + | ==Заменить версию Кассира== | |
| − | + | Заменить '''zkassa.exe''' на версию '''2.2.1.17''' от апреля 2016 г. или более новую. | |
| + | ==Выполняем скрипт== | ||
<pre> | <pre> | ||
| + | /******************************************************************************/ | ||
| + | /*** Generated by IBExpert 18.04.2016 9:25:20 ***/ | ||
| + | /******************************************************************************/ | ||
| + | |||
| + | /******************************************************************************/ | ||
| + | /*** Following SET SQL DIALECT is just for the Database Comparer ***/ | ||
| + | /******************************************************************************/ | ||
| + | SET SQL DIALECT 3; | ||
| + | |||
| + | |||
| + | |||
| + | /******************************************************************************/ | ||
| + | /*** Tables ***/ | ||
| + | /******************************************************************************/ | ||
| + | |||
| + | |||
| + | |||
| + | CREATE TABLE DSC_RULES ( | ||
| + | ID INTEGER NOT NULL, | ||
| + | DATE_BEG DM_DATE NOT NULL /* DM_DATE = DATE */, | ||
| + | DATE_END DM_DATE NOT NULL /* DM_DATE = DATE */, | ||
| + | MMBSH1 DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | NDS_O1 DM_ID_NULL /* DM_ID_NULL = BIGINT */, | ||
| + | SNAME1 DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | SNAME2 DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | SNAME3 DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | SNAME4 DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | SNAME5 DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | PRICE_MIN DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */, | ||
| + | PRICE_MAX DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */, | ||
| + | QUANT_DIV DM_ID_NULL /* DM_ID_NULL = BIGINT */, | ||
| + | QUANT_DSC DM_ID_NULL /* DM_ID_NULL = BIGINT */, | ||
| + | SUM_DSC DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */, | ||
| + | PERC_DSC DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */, | ||
| + | BARCODE_DSC DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | STATUS SMALLINT NOT NULL, | ||
| + | COMMENTS DM_TEXT /* DM_TEXT = VARCHAR(250) */, | ||
| + | D$UUID DM_UUID /* DM_UUID = CHAR(36) NOT NULL */, | ||
| + | D$SRVUPDDT DM_DATETIME /* DM_DATETIME = TIMESTAMP */ | ||
| + | ); | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | /******************************************************************************/ | ||
| + | /*** Triggers ***/ | ||
| + | /******************************************************************************/ | ||
| + | |||
| + | |||
| + | SET TERM ^ ; | ||
| + | |||
| + | |||
| + | |||
| + | /******************************************************************************/ | ||
| + | /*** Triggers for tables ***/ | ||
| + | /******************************************************************************/ | ||
| + | |||
| + | |||
| + | |||
| + | /* Trigger: DSC_RULES_AD_DISTR */ | ||
| + | CREATE OR ALTER TRIGGER DSC_RULES_AD_DISTR FOR DSC_RULES | ||
| + | ACTIVE AFTER DELETE POSITION 0 | ||
| + | AS | ||
| + | begin | ||
| + | update or insert into g$distribute (TABLENAME,UUID,SOPER,FROM_PROFILE_ID) values ('DSC_RULES',old.d$uuid,2,null) | ||
| + | matching (TABLENAME,UUID); | ||
| + | end | ||
| + | ^ | ||
| + | |||
| + | |||
| + | /* Trigger: DSC_RULES_BI0 */ | ||
| + | CREATE OR ALTER TRIGGER DSC_RULES_BI0 FOR DSC_RULES | ||
| + | ACTIVE BEFORE INSERT POSITION 0 | ||
| + | AS | ||
| + | begin | ||
| + | select max(id)+1 from DSC_RULES into new.id; | ||
| + | if (new.id is null) then new.id = 1; | ||
| + | end | ||
| + | ^ | ||
| + | |||
| + | |||
| + | /* Trigger: DSC_RULES_BIU0 */ | ||
| + | CREATE OR ALTER TRIGGER DSC_RULES_BIU0 FOR DSC_RULES | ||
| + | ACTIVE BEFORE INSERT OR UPDATE POSITION 0 | ||
| + | AS | ||
| + | begin | ||
| + | new.mmbsh1 = UPPER(new.mmbsh1); | ||
| + | new.sname1 = UPPER(new.sname1); | ||
| + | new.sname2 = UPPER(new.sname2); | ||
| + | new.sname3 = UPPER(new.sname3); | ||
| + | new.sname4 = UPPER(new.sname4); | ||
| + | new.sname5 = UPPER(new.sname5); | ||
| + | end | ||
| + | ^ | ||
| + | |||
| + | |||
| + | /* Trigger: DSC_RULES_BI_DISTR */ | ||
| + | CREATE OR ALTER TRIGGER DSC_RULES_BI_DISTR FOR DSC_RULES | ||
| + | ACTIVE BEFORE INSERT POSITION 9999 | ||
| + | AS | ||
| + | begin | ||
| + | if (new.d$uuid is null) then | ||
| + | begin | ||
| + | new.d$uuid=UUID_TO_CHAR(GEN_UUID()); | ||
| + | new.d$srvupddt='2000-01-01'; | ||
| + | update or insert into g$distribute (TABLENAME,UUID,SOPER,FROM_PROFILE_ID) values ('DSC_RULES',new.d$uuid,0,null) matching (TABLENAME,UUID); | ||
| + | end | ||
| + | end | ||
| + | ^ | ||
| + | |||
| + | |||
| + | /* Trigger: DSC_RULES_BU_DISTR */ | ||
| + | CREATE OR ALTER TRIGGER DSC_RULES_BU_DISTR FOR DSC_RULES | ||
| + | ACTIVE BEFORE UPDATE POSITION 0 | ||
| + | AS | ||
| + | begin | ||
| + | if (new.D$SRVUPDDT=old.D$SRVUPDDT) then | ||
| + | update or insert into g$distribute (TABLENAME,UUID,SOPER,FROM_PROFILE_ID) values ('DSC_RULES',new.d$uuid,1,null) | ||
| + | matching (TABLENAME,UUID); | ||
| + | end | ||
| + | ^ | ||
| + | |||
| + | |||
| + | SET TERM ; ^ | ||
| + | |||
| + | |||
| + | |||
| + | /******************************************************************************/ | ||
| + | /*** Privileges ***/ | ||
| + | /******************************************************************************/ | ||
| + | |||
| + | |||
| + | SET TERM ^ ; | ||
| + | |||
| + | create or alter procedure PR_GET_DSC_RULES ( | ||
| + | PART_ID_IN DM_ID, | ||
| + | DOC_ID DM_ID, | ||
| + | DEL integer = 0) | ||
| + | returns ( | ||
| + | PART_ID_OUT integer, | ||
| + | DISCOUNT DM_DOUBLE, | ||
| + | BARCODE_DSC DM_TEXT) | ||
| + | as | ||
| + | declare variable SNAME DM_TEXT; | ||
| + | declare variable PRICE DM_DOUBLE; | ||
| + | declare variable QUANT DM_DOUBLE; | ||
| + | declare variable SNAME1 DM_TEXT; | ||
| + | declare variable SNAME2 DM_TEXT; | ||
| + | declare variable SNAME3 DM_TEXT; | ||
| + | declare variable SNAME4 DM_TEXT; | ||
| + | declare variable SNAME5 DM_TEXT; | ||
| + | declare variable PRICE_MIN DM_DOUBLE; | ||
| + | declare variable PRICE_MAX DM_DOUBLE; | ||
| + | declare variable QUANT_DIV DM_ID; | ||
| + | declare variable QUANT_DSC DM_ID; | ||
| + | declare variable SUM_DSC DM_DOUBLE; | ||
| + | declare variable PERC_DSC DM_DOUBLE; | ||
| + | declare variable MAX_PART_ID DM_ID; | ||
| + | declare variable SUM_QUANT DM_DOUBLE; | ||
| + | declare variable NO_DSC integer; | ||
| + | declare variable CONST_MAX_PRICE integer; | ||
| + | declare variable MMBSH DM_TEXT1024; | ||
| + | declare variable NDS_O DM_ID_NULL; | ||
| + | declare variable MMBSH1 DM_TEXT; | ||
| + | declare variable NDS_O1 DM_ID_NULL; | ||
| + | declare variable BARCODE DM_TEXT; | ||
| + | begin | ||
| + | -------------------- Описание параметров --------------------------------------------------- | ||
| + | --Процедура вызывается в кассире в событиях -305 и -332 | ||
| + | --PART_ID_IN - партия, по которой изменили кол-во/добавили/удалили в чеке, и на которую необходимо рассчитать скидку | ||
| + | --DOC_ID - чек | ||
| + | --DEL - признак, что партию удаляют из чека | ||
| + | |||
| + | --PART_ID_OUT - список партий по которым нужно обновить скидку | ||
| + | --DISCOUNT - скидка в рублях | ||
| + | --BARCODE_DSC - штрихкод скидки, который нужно применить (суммовая скидка работает быстрее, лучше использовать её) | ||
| + | |||
| + | ------------------- Описание DSC_RULES ------------------------------------------------------ | ||
| + | --DATE_BEG и DATE_END - период действия скидки | ||
| + | --MMBSH1 - группа товара | ||
| + | --NDS_O1 - ставка НДС опт (10,18,12 ....) | ||
| + | --SNAME1 ... SNAME5 - слова, которым должна соответствовать позиция для того, чтобы скидка назначилась (все не обязательны) | ||
| + | --PRICE_MIN и PRICE_MAX - ценовой диапазон, которому должна соответствовать позиция, чтобы скидка назначилась (все не обязательны) | ||
| + | --QUANT_DIV и QUANT_DSC, для условий типа: при покупке 4х штук (QUANT_DIV) одна(QUANT_DSC) в подарок | ||
| + | --SUM_DSC - суммовая скидка на позицию в рублях | ||
| + | --PERC_DSC - процентная скидка на позицию в % (например 0.15) | ||
| + | --BARCODE_DSC - штрихкод скидки, который нужно применить (суммовая скидка работает быстрее, лучше использовать её) | ||
| + | --STATUS, 1 - правило активно, 0 - неактивно | ||
| + | |||
| + | CONST_MAX_PRICE = 99999; | ||
| + | DISCOUNT = 0; | ||
| + | PART_ID_OUT = PART_ID_IN; | ||
| + | |||
| + | select UPPER(sname), price, abs(quant), coalesce(nds,0), UPPER(mmbsh) from vw_doc_detail_active where doc_id = :doc_id and part_id = :part_id_in into :sname, :price, :quant, :nds_o, :mmbsh; | ||
| + | |||
| + | for select MMBSH1, NDS_O1, SNAME1,SNAME2,SNAME3,SNAME4,SNAME5,PRICE_MIN,PRICE_MAX,QUANT_DIV,QUANT_DSC,SUM_DSC,PERC_DSC,BARCODE_DSC | ||
| + | from DSC_RULES dr where status = 1 and dr.date_beg <= current_date and dr.date_end >= current_date | ||
| + | into :MMBSH1, :NDS_O1, :SNAME1,:SNAME2,:SNAME3,:SNAME4,:SNAME5,:PRICE_MIN,:PRICE_MAX,:QUANT_DIV,:QUANT_DSC,:SUM_DSC,:PERC_DSC,:BARCODE do | ||
| + | begin | ||
| + | NO_DSC = 0; | ||
| + | |||
| + | if (:MMBSH1 is null) then MMBSH1 = ''; | ||
| + | if (:SNAME1 is null) then SNAME1 = ''; | ||
| + | if (:SNAME2 is null) then SNAME2 = ''; | ||
| + | if (:SNAME3 is null) then SNAME3 = ''; | ||
| + | if (:SNAME4 is null) then SNAME4 = ''; | ||
| + | if (:SNAME5 is null) then SNAME5 = ''; | ||
| + | |||
| + | --Проверка на группу | ||
| + | if (NO_DSC = 0) then | ||
| + | if ( Not(MMBSH containing MMBSH1) ) Then | ||
| + | NO_DSC = 1; | ||
| + | |||
| + | --Проверка на НДС | ||
| + | if (NO_DSC = 0) then | ||
| + | if((:NDS_O1 is not null) and (:NDS_O1 <> :NDS_O)) Then | ||
| + | NO_DSC = 1; | ||
| + | |||
| + | --Проверка на наименование | ||
| + | if (NO_DSC = 0) then | ||
| + | if (Not((sname containing SNAME1) and (sname containing SNAME2) and (sname containing SNAME3) and (sname containing SNAME4) and (sname containing SNAME5))) Then | ||
| + | NO_DSC = 1; | ||
| + | |||
| + | --Проверка на цену | ||
| + | if (NO_DSC = 0) then | ||
| + | if ( (price < coalesce(PRICE_MIN,0)) or | ||
| + | (price > coalesce(PRICE_MAX,CONST_MAX_PRICE)) ) Then | ||
| + | NO_DSC = 1; | ||
| + | |||
| + | --Проверка на кратность | ||
| + | if (NO_DSC = 0) then | ||
| + | if (QUANT_DIV is not null) then | ||
| + | begin | ||
| + | --Определяем партию на которую будем назначать скидку | ||
| + | select max(part_id), abs(sum(quant)), min(price) from vw_doc_detail_active da where doc_id = :doc_id | ||
| + | and UPPER(da.sname) containing :SNAME1 | ||
| + | and UPPER(da.sname) containing :SNAME2 | ||
| + | and UPPER(da.sname) containing :SNAME3 | ||
| + | and UPPER(da.sname) containing :SNAME4 | ||
| + | and UPPER(da.sname) containing :SNAME5 | ||
| + | and ( ((:DEL = 1) and (part_id <> :PART_ID_IN)) or (:DEL = 0) ) | ||
| + | and (price >= coalesce(:PRICE_MIN,0)) and (price <= coalesce(:PRICE_MAX,:CONST_MAX_PRICE)) | ||
| + | and UPPER(da.MMBSH) containing :MMBSH1 | ||
| + | and ( (:NDS_O1 is null) or ((:NDS_O1 is not null) and (:NDS_O1 = NDS)) ) | ||
| + | into :max_part_id, :sum_quant, :price; | ||
| + | --Скидка назначается только на партию с максимальным ID и если условие кратности соблюдается | ||
| + | --По всем остальным партиям скидку сбрасываем | ||
| + | for select part_id from vw_doc_detail_active da where doc_id = :doc_id and UPPER(da.sname) containing :SNAME1 | ||
| + | and UPPER(da.sname) containing :SNAME2 | ||
| + | and UPPER(da.sname) containing :SNAME3 | ||
| + | and UPPER(da.sname) containing :SNAME4 | ||
| + | and UPPER(da.sname) containing :SNAME5 | ||
| + | and ( ((:DEL = 1) and (part_id <> :PART_ID_IN)) or (:DEL = 0) ) | ||
| + | and (price >= coalesce(:PRICE_MIN,0)) and (price <= coalesce(:PRICE_MAX,:CONST_MAX_PRICE)) | ||
| + | and UPPER(da.MMBSH) containing :MMBSH1 | ||
| + | and ( (:NDS_O1 is null) or ((:NDS_O1 is not null) and (:NDS_O1 = NDS)) ) | ||
| + | into :PART_ID_OUT do | ||
| + | Begin | ||
| + | if ((max_part_id = PART_ID_OUT) and (Trunc(sum_quant/QUANT_DIV) > 0)) then | ||
| + | begin | ||
| + | if (QUANT_DSC is not null) then DISCOUNT = QUANT_DSC*:price*Trunc(sum_quant/QUANT_DIV); | ||
| + | if (SUM_DSC is not null) then DISCOUNT = SUM_DSC*Trunc(sum_quant/QUANT_DIV); | ||
| + | if (PERC_DSC is not null) then DISCOUNT = :quant*:price*PERC_DSC; | ||
| + | if (BARCODE is not null) then BARCODE_DSC = :BARCODE; | ||
| + | end | ||
| + | else | ||
| + | Begin | ||
| + | DISCOUNT = 0; | ||
| + | BARCODE_DSC = Null; | ||
| + | end | ||
| + | suspend; | ||
| + | End | ||
| + | exit; | ||
| + | End | ||
| + | |||
| + | --Суммовая скидка | ||
| + | if ( (NO_DSC = 0) and (DEL = 0) and ((SUM_DSC is not null) or (BARCODE is not null)) ) then | ||
| + | Begin | ||
| + | DISCOUNT = :quant*SUM_DSC; | ||
| + | BARCODE_DSC = BARCODE; | ||
| + | suspend; | ||
| + | exit; | ||
| + | End | ||
| + | |||
| + | --Процентная скидка | ||
| + | if ( (NO_DSC = 0) and (DEL = 0) and ((PERC_DSC is not null) or (BARCODE is not null)) ) then | ||
| + | Begin | ||
| + | DISCOUNT = :quant*:price*PERC_DSC; | ||
| + | BARCODE_DSC = BARCODE; | ||
| + | suspend; | ||
| + | exit; | ||
| + | End | ||
| + | |||
| + | End | ||
| + | end^ | ||
| + | |||
| + | SET TERM ; ^ | ||
| + | |||
| + | /* Following GRANT statetements are generated automatically */ | ||
| + | |||
| + | GRANT SELECT ON VW_DOC_DETAIL_ACTIVE TO PROCEDURE PR_GET_DSC_RULES; | ||
| + | GRANT SELECT ON DSC_RULES TO PROCEDURE PR_GET_DSC_RULES; | ||
| + | |||
| + | /* Existing privileges on this procedure */ | ||
| + | |||
| + | GRANT EXECUTE ON PROCEDURE PR_GET_DSC_RULES TO SYSDBA; | ||
| + | </PRE> | ||
| + | |||
| + | ==Создаем в кассире ТМС== | ||
| + | <PRE> | ||
uses | uses | ||
Graphics, Controls, Forms, Dialogs, StdCtrls, | Graphics, Controls, Forms, Dialogs, StdCtrls, | ||
| Строка 10: | Строка 321: | ||
ScriptRes, Barcode,ZKassa, StrUtils, Windows, Classes, | ScriptRes, Barcode,ZKassa, StrUtils, Windows, Classes, | ||
IBDataBase, SysUtils, DateUtils, chequelist; | IBDataBase, SysUtils, DateUtils, chequelist; | ||
| + | |||
| + | Procedure RecalcDSC(del:integer) | ||
var iq: tibquery; | var iq: tibquery; | ||
| − | |||
| − | |||
begin | begin | ||
Try | Try | ||
| Строка 19: | Строка 330: | ||
iq.transaction.starttransaction; | iq.transaction.starttransaction; | ||
iq.active := False; | iq.active := False; | ||
| − | |||
| − | + | iq.sql.text := 'select * from PR_GET_DSC_RULES('+IntToStr(ChequeList.ActivePID)+','+IntToStr(ChequeList.Active.ID)+','+IntToStr(del)+')'; | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | iq.sql.text := 'select | + | |
iq.active := True; | iq.active := True; | ||
| − | + | while not (iq.Eof) do | |
| − | + | begin | |
| − | + | ChequeList.Active.P_Index:= ChequeList.Active.IndexByPartID(iq.FieldByName('part_id_out').AsInteger); | |
| − | + | if (iq.FieldByName('BARCODE_DSC').AsString = '') Then | |
| − | ChequeList.Active.P_Index:= ChequeList.Active.IndexByPartID( | + | ChequeList.Active.P_SetDiscount(-1*iq.FieldByName('DISCOUNT').AsFloat) |
| − | ChequeList.Active.P_SetDiscount( | + | else |
| − | + | Barcode.ApplyDiscount(iq.FieldByName('BARCODE_DSC').AsString, iq.FieldByName('part_id_out').AsInteger); | |
| − | + | iq.next; | |
| − | + | End; | |
| + | finally | ||
| + | iq.active := False; | ||
| + | iq.transaction.free; | ||
| + | iq.free; | ||
| + | end; | ||
| − | + | end; | |
| − | + | </PRE> | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | '''Вызываем RecalcDSC в ТМС''' | |
| − | + | '''-305 как RecalcDSC(0); ''' | |
| − | + | '''-332 как RecalcDSC(1); ''' | |
| − | + | Скрипт должен выглядеть примерно так: | |
| − | + | <PRE> | |
| − | + | uses | |
| − | + | p10112u1; | |
| − | + | begin | |
| − | + | RecalcDSC(0); | |
| − | + | end; | |
| − | + | </PRE> | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | </ | + | |
| + | ==Пример №2 (старый мех-м)== | ||
| + | * акция действует всегда пока включен переключатель в параметрах системы | ||
| + | <PRE> | ||
| + | INSERT INTO PARAMS ( PARENT_ID, PARAM_ID, PARAM_CAPTION, PARAM_TYPE, PARAM_VALUE, AUDIT_ID, IMAGEINDEX, | ||
| + | STATUS, INSERTDT, SORTING, PARAM_TYPE_DATA, PACKET) VALUES ( -30, 'AKCCII_TOGGLE', 'Включение акций', 14, '0', 3229, NULL, 0, '19-DEC-2015 10:45:34.828', NULL, 'FIXEDITEMS SHOWONLYVALUES RETURNNAME | ||
| + | 0=выключено | ||
| + | 1=включено'); | ||
| + | </PRE> | ||
| + | * если переключатель включен - в кассире при продаже активируется скидка = разнице между заполненными колонками price и ещё одной ценовой колонкой, ниже использована PRICE_R | ||
| − | + | <PRE> | |
| − | + | uses | |
| − | + | Graphics, Controls, Forms, Dialogs, StdCtrls, | |
| − | + | ComCtrls, ExtCtrls, ibquery, DB, ChequeList, FR, | |
| − | + | ScriptRes, Barcode,ZKassa, StrUtils, Windows, Classes, | |
| + | IBDataBase, SysUtils, DateUtils, chequelist; | ||
| + | var iq: tibquery; | ||
| + | dsc, part_id: integer; | ||
| + | discount: float; | ||
| + | begin | ||
| + | Try | ||
| + | iq := tibquery.create(nil); | ||
| + | iq.transaction := CreateRT(CurrDB); | ||
| + | iq.transaction.starttransaction; | ||
| + | iq.active := False; | ||
| − | + | iq.sql.text := 'select wb.part_id,wb.PRICE_R,(select p.param_value from params p where p.param_id = ''AKCCII_TOGGLE'') from vw_warebase wb where wb.part_id = '+ | |
| − | + | IntToStr(ChequeList.ActivePID); | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | iq.sql.text := 'select | + | |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | == | + | iq.active := True; |
| − | + | if not(iq.Eof) then | |
| − | + | if ( not iq.FieldByName('param_value').AsInteger=0 )then | |
| − | + | if ( not iq.FieldByName('PRICE_R').isNull )then | |
| + | if (iq.FieldByName('PRICE_R').AsFloat>0) then begin | ||
| + | ChequeList.Active.P_Index := ChequeList.Active.IndexByPartID(iq.FieldByName('part_id').AsInteger); | ||
| + | temp := -(ChequeList.Active.P_Price - iq.FieldByName('PRICE_R').AsFloat); | ||
| + | ChequeList.Active.P_SetDiscount(temp); | ||
| + | end; | ||
finally | finally | ||
iq.active := False; | iq.active := False; | ||
| Строка 141: | Строка 408: | ||
end; | end; | ||
| − | + | </PRE> | |
| − | </ | + | |
| + | =Отправка ТМС по синхронизации= | ||
| + | |||
| + | ==Выгружаем тмс из базы из blob поля в файл== | ||
| + | Тмс можно найти спомощью запроса: | ||
| + | select * from groups g where g.id=-305 | ||
| + | |||
| + | Затем сохраняем на жесткий диск тмс из поля '''data'''. | ||
| + | |||
| + | ==Загружаем ТМС в серверную базу== | ||
| + | * В таблице '''g$profiles''' выбираем blob поле, которое будем использовать для отправки, например '''TMP_BLOB1'''. | ||
| + | * Убеждаемся, что данная таблица синхронизируется в двухстороннем направлении. | ||
| + | * Загружаем в это поле например первому профилю наш ТМС скрипт. | ||
| + | * Ждем когда это обновление придет всем по синхронизации. | ||
| + | |||
| + | ==Применяем всем ТМС== | ||
| + | По '''g$tasks''' отправляем запрос нужным профилям: | ||
| + | update groups gp set gp.data = (select g.tmp_blob1 from G$PROFILES g where g.id = 1) where gp.id = -305; | ||
| + | |||
| + | =Примеры акций= | ||
| + | 1. Акция на апрель, Эссенциале №30 - скидка 150 руб за каждую упаковку | ||
| + | 2. Акция до конца мая, на Магне №50 (с ценой от 500 до 1000 руб) - при покупке 4х упаковок 1 в подарок; | ||
| + | 3. Акция на Ферверкс, при покупке 2х упаковок 1 в подарок; | ||
| + | 4. Аналогично Ферверксу, только на Маалокс; | ||
| + | 5 и 6. На зодак №7 и №28 скидка 15%; | ||
| + | 7. Акция на Эмолиум, при покупке 2х упаковок скидка 350 руб.; | ||
| + | 8. Аналогично, на Фитолизин - 100 руб.; | ||
| + | 9. На все ЖНВЛС скидка 5%; | ||
| + | 10. На все товары с НДС опт. 10%, - скидка 10%; | ||
| + | 11. На все товары с НДС опт. 18%, - скидка 15%; | ||
| + | |||
| + | [[Файл:Примеры_акций.png|Окно программы]] | ||
| + | |||
| + | * '''DATE_BEG''' и '''DATE_END''' - период действия скидки | ||
| + | * '''MMBSH1''' - группа товара | ||
| + | * '''NDS_O1''' - ставка НДС опт (10,18,12 ....) | ||
| + | * '''SNAME1''' ... '''SNAME5''' - слова, которым должна соответствовать позиция для того, чтобы скидка назначилась (все не обязательны) | ||
| + | * '''PRICE_MIN''' и '''PRICE_MAX''' - ценовой диапазон, которому должна соответствовать позиция, чтобы скидка назначилась (все не обязательны) | ||
| + | * '''QUANT_DIV''' и '''QUANT_DSC''', для условий типа: при покупке 4х штук (QUANT_DIV) одна(QUANT_DSC) в подарок | ||
| + | * '''SUM_DSC''' - суммовая скидка на позицию в рублях | ||
| + | * '''PERC_DSC''' - процентная скидка на позицию в % (например 0.15) | ||
| + | * '''STATUS''', 1 - правило активно, 0 - неактивно | ||
| + | |||
| + | |||
| + | [[Problems:Настройка системы скидок для сети|'''ПОСМОТРЕТЬ ЕЩЕ ПРИМЕРЫ''']] | ||
| + | |||
| + | |||
| + | =Видео= | ||
| + | * [[Файл:Ролик по акциям2.mp4]] | ||
Текущая версия на 16:58, 14 сентября 2018
Содержание
Настройка ТМС Акции в кассире
Заменить версию Кассира
Заменить zkassa.exe на версию 2.2.1.17 от апреля 2016 г. или более новую.
Выполняем скрипт
/******************************************************************************/
/*** Generated by IBExpert 18.04.2016 9:25:20 ***/
/******************************************************************************/
/******************************************************************************/
/*** Following SET SQL DIALECT is just for the Database Comparer ***/
/******************************************************************************/
SET SQL DIALECT 3;
/******************************************************************************/
/*** Tables ***/
/******************************************************************************/
CREATE TABLE DSC_RULES (
ID INTEGER NOT NULL,
DATE_BEG DM_DATE NOT NULL /* DM_DATE = DATE */,
DATE_END DM_DATE NOT NULL /* DM_DATE = DATE */,
MMBSH1 DM_TEXT /* DM_TEXT = VARCHAR(250) */,
NDS_O1 DM_ID_NULL /* DM_ID_NULL = BIGINT */,
SNAME1 DM_TEXT /* DM_TEXT = VARCHAR(250) */,
SNAME2 DM_TEXT /* DM_TEXT = VARCHAR(250) */,
SNAME3 DM_TEXT /* DM_TEXT = VARCHAR(250) */,
SNAME4 DM_TEXT /* DM_TEXT = VARCHAR(250) */,
SNAME5 DM_TEXT /* DM_TEXT = VARCHAR(250) */,
PRICE_MIN DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
PRICE_MAX DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
QUANT_DIV DM_ID_NULL /* DM_ID_NULL = BIGINT */,
QUANT_DSC DM_ID_NULL /* DM_ID_NULL = BIGINT */,
SUM_DSC DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
PERC_DSC DM_DOUBLE /* DM_DOUBLE = DOUBLE PRECISION */,
BARCODE_DSC DM_TEXT /* DM_TEXT = VARCHAR(250) */,
STATUS SMALLINT NOT NULL,
COMMENTS DM_TEXT /* DM_TEXT = VARCHAR(250) */,
D$UUID DM_UUID /* DM_UUID = CHAR(36) NOT NULL */,
D$SRVUPDDT DM_DATETIME /* DM_DATETIME = TIMESTAMP */
);
/******************************************************************************/
/*** Triggers ***/
/******************************************************************************/
SET TERM ^ ;
/******************************************************************************/
/*** Triggers for tables ***/
/******************************************************************************/
/* Trigger: DSC_RULES_AD_DISTR */
CREATE OR ALTER TRIGGER DSC_RULES_AD_DISTR FOR DSC_RULES
ACTIVE AFTER DELETE POSITION 0
AS
begin
update or insert into g$distribute (TABLENAME,UUID,SOPER,FROM_PROFILE_ID) values ('DSC_RULES',old.d$uuid,2,null)
matching (TABLENAME,UUID);
end
^
/* Trigger: DSC_RULES_BI0 */
CREATE OR ALTER TRIGGER DSC_RULES_BI0 FOR DSC_RULES
ACTIVE BEFORE INSERT POSITION 0
AS
begin
select max(id)+1 from DSC_RULES into new.id;
if (new.id is null) then new.id = 1;
end
^
/* Trigger: DSC_RULES_BIU0 */
CREATE OR ALTER TRIGGER DSC_RULES_BIU0 FOR DSC_RULES
ACTIVE BEFORE INSERT OR UPDATE POSITION 0
AS
begin
new.mmbsh1 = UPPER(new.mmbsh1);
new.sname1 = UPPER(new.sname1);
new.sname2 = UPPER(new.sname2);
new.sname3 = UPPER(new.sname3);
new.sname4 = UPPER(new.sname4);
new.sname5 = UPPER(new.sname5);
end
^
/* Trigger: DSC_RULES_BI_DISTR */
CREATE OR ALTER TRIGGER DSC_RULES_BI_DISTR FOR DSC_RULES
ACTIVE BEFORE INSERT POSITION 9999
AS
begin
if (new.d$uuid is null) then
begin
new.d$uuid=UUID_TO_CHAR(GEN_UUID());
new.d$srvupddt='2000-01-01';
update or insert into g$distribute (TABLENAME,UUID,SOPER,FROM_PROFILE_ID) values ('DSC_RULES',new.d$uuid,0,null) matching (TABLENAME,UUID);
end
end
^
/* Trigger: DSC_RULES_BU_DISTR */
CREATE OR ALTER TRIGGER DSC_RULES_BU_DISTR FOR DSC_RULES
ACTIVE BEFORE UPDATE POSITION 0
AS
begin
if (new.D$SRVUPDDT=old.D$SRVUPDDT) then
update or insert into g$distribute (TABLENAME,UUID,SOPER,FROM_PROFILE_ID) values ('DSC_RULES',new.d$uuid,1,null)
matching (TABLENAME,UUID);
end
^
SET TERM ; ^
/******************************************************************************/
/*** Privileges ***/
/******************************************************************************/
SET TERM ^ ;
create or alter procedure PR_GET_DSC_RULES (
PART_ID_IN DM_ID,
DOC_ID DM_ID,
DEL integer = 0)
returns (
PART_ID_OUT integer,
DISCOUNT DM_DOUBLE,
BARCODE_DSC DM_TEXT)
as
declare variable SNAME DM_TEXT;
declare variable PRICE DM_DOUBLE;
declare variable QUANT DM_DOUBLE;
declare variable SNAME1 DM_TEXT;
declare variable SNAME2 DM_TEXT;
declare variable SNAME3 DM_TEXT;
declare variable SNAME4 DM_TEXT;
declare variable SNAME5 DM_TEXT;
declare variable PRICE_MIN DM_DOUBLE;
declare variable PRICE_MAX DM_DOUBLE;
declare variable QUANT_DIV DM_ID;
declare variable QUANT_DSC DM_ID;
declare variable SUM_DSC DM_DOUBLE;
declare variable PERC_DSC DM_DOUBLE;
declare variable MAX_PART_ID DM_ID;
declare variable SUM_QUANT DM_DOUBLE;
declare variable NO_DSC integer;
declare variable CONST_MAX_PRICE integer;
declare variable MMBSH DM_TEXT1024;
declare variable NDS_O DM_ID_NULL;
declare variable MMBSH1 DM_TEXT;
declare variable NDS_O1 DM_ID_NULL;
declare variable BARCODE DM_TEXT;
begin
-------------------- Описание параметров ---------------------------------------------------
--Процедура вызывается в кассире в событиях -305 и -332
--PART_ID_IN - партия, по которой изменили кол-во/добавили/удалили в чеке, и на которую необходимо рассчитать скидку
--DOC_ID - чек
--DEL - признак, что партию удаляют из чека
--PART_ID_OUT - список партий по которым нужно обновить скидку
--DISCOUNT - скидка в рублях
--BARCODE_DSC - штрихкод скидки, который нужно применить (суммовая скидка работает быстрее, лучше использовать её)
------------------- Описание DSC_RULES ------------------------------------------------------
--DATE_BEG и DATE_END - период действия скидки
--MMBSH1 - группа товара
--NDS_O1 - ставка НДС опт (10,18,12 ....)
--SNAME1 ... SNAME5 - слова, которым должна соответствовать позиция для того, чтобы скидка назначилась (все не обязательны)
--PRICE_MIN и PRICE_MAX - ценовой диапазон, которому должна соответствовать позиция, чтобы скидка назначилась (все не обязательны)
--QUANT_DIV и QUANT_DSC, для условий типа: при покупке 4х штук (QUANT_DIV) одна(QUANT_DSC) в подарок
--SUM_DSC - суммовая скидка на позицию в рублях
--PERC_DSC - процентная скидка на позицию в % (например 0.15)
--BARCODE_DSC - штрихкод скидки, который нужно применить (суммовая скидка работает быстрее, лучше использовать её)
--STATUS, 1 - правило активно, 0 - неактивно
CONST_MAX_PRICE = 99999;
DISCOUNT = 0;
PART_ID_OUT = PART_ID_IN;
select UPPER(sname), price, abs(quant), coalesce(nds,0), UPPER(mmbsh) from vw_doc_detail_active where doc_id = :doc_id and part_id = :part_id_in into :sname, :price, :quant, :nds_o, :mmbsh;
for select MMBSH1, NDS_O1, SNAME1,SNAME2,SNAME3,SNAME4,SNAME5,PRICE_MIN,PRICE_MAX,QUANT_DIV,QUANT_DSC,SUM_DSC,PERC_DSC,BARCODE_DSC
from DSC_RULES dr where status = 1 and dr.date_beg <= current_date and dr.date_end >= current_date
into :MMBSH1, :NDS_O1, :SNAME1,:SNAME2,:SNAME3,:SNAME4,:SNAME5,:PRICE_MIN,:PRICE_MAX,:QUANT_DIV,:QUANT_DSC,:SUM_DSC,:PERC_DSC,:BARCODE do
begin
NO_DSC = 0;
if (:MMBSH1 is null) then MMBSH1 = '';
if (:SNAME1 is null) then SNAME1 = '';
if (:SNAME2 is null) then SNAME2 = '';
if (:SNAME3 is null) then SNAME3 = '';
if (:SNAME4 is null) then SNAME4 = '';
if (:SNAME5 is null) then SNAME5 = '';
--Проверка на группу
if (NO_DSC = 0) then
if ( Not(MMBSH containing MMBSH1) ) Then
NO_DSC = 1;
--Проверка на НДС
if (NO_DSC = 0) then
if((:NDS_O1 is not null) and (:NDS_O1 <> :NDS_O)) Then
NO_DSC = 1;
--Проверка на наименование
if (NO_DSC = 0) then
if (Not((sname containing SNAME1) and (sname containing SNAME2) and (sname containing SNAME3) and (sname containing SNAME4) and (sname containing SNAME5))) Then
NO_DSC = 1;
--Проверка на цену
if (NO_DSC = 0) then
if ( (price < coalesce(PRICE_MIN,0)) or
(price > coalesce(PRICE_MAX,CONST_MAX_PRICE)) ) Then
NO_DSC = 1;
--Проверка на кратность
if (NO_DSC = 0) then
if (QUANT_DIV is not null) then
begin
--Определяем партию на которую будем назначать скидку
select max(part_id), abs(sum(quant)), min(price) from vw_doc_detail_active da where doc_id = :doc_id
and UPPER(da.sname) containing :SNAME1
and UPPER(da.sname) containing :SNAME2
and UPPER(da.sname) containing :SNAME3
and UPPER(da.sname) containing :SNAME4
and UPPER(da.sname) containing :SNAME5
and ( ((:DEL = 1) and (part_id <> :PART_ID_IN)) or (:DEL = 0) )
and (price >= coalesce(:PRICE_MIN,0)) and (price <= coalesce(:PRICE_MAX,:CONST_MAX_PRICE))
and UPPER(da.MMBSH) containing :MMBSH1
and ( (:NDS_O1 is null) or ((:NDS_O1 is not null) and (:NDS_O1 = NDS)) )
into :max_part_id, :sum_quant, :price;
--Скидка назначается только на партию с максимальным ID и если условие кратности соблюдается
--По всем остальным партиям скидку сбрасываем
for select part_id from vw_doc_detail_active da where doc_id = :doc_id and UPPER(da.sname) containing :SNAME1
and UPPER(da.sname) containing :SNAME2
and UPPER(da.sname) containing :SNAME3
and UPPER(da.sname) containing :SNAME4
and UPPER(da.sname) containing :SNAME5
and ( ((:DEL = 1) and (part_id <> :PART_ID_IN)) or (:DEL = 0) )
and (price >= coalesce(:PRICE_MIN,0)) and (price <= coalesce(:PRICE_MAX,:CONST_MAX_PRICE))
and UPPER(da.MMBSH) containing :MMBSH1
and ( (:NDS_O1 is null) or ((:NDS_O1 is not null) and (:NDS_O1 = NDS)) )
into :PART_ID_OUT do
Begin
if ((max_part_id = PART_ID_OUT) and (Trunc(sum_quant/QUANT_DIV) > 0)) then
begin
if (QUANT_DSC is not null) then DISCOUNT = QUANT_DSC*:price*Trunc(sum_quant/QUANT_DIV);
if (SUM_DSC is not null) then DISCOUNT = SUM_DSC*Trunc(sum_quant/QUANT_DIV);
if (PERC_DSC is not null) then DISCOUNT = :quant*:price*PERC_DSC;
if (BARCODE is not null) then BARCODE_DSC = :BARCODE;
end
else
Begin
DISCOUNT = 0;
BARCODE_DSC = Null;
end
suspend;
End
exit;
End
--Суммовая скидка
if ( (NO_DSC = 0) and (DEL = 0) and ((SUM_DSC is not null) or (BARCODE is not null)) ) then
Begin
DISCOUNT = :quant*SUM_DSC;
BARCODE_DSC = BARCODE;
suspend;
exit;
End
--Процентная скидка
if ( (NO_DSC = 0) and (DEL = 0) and ((PERC_DSC is not null) or (BARCODE is not null)) ) then
Begin
DISCOUNT = :quant*:price*PERC_DSC;
BARCODE_DSC = BARCODE;
suspend;
exit;
End
End
end^
SET TERM ; ^
/* Following GRANT statetements are generated automatically */
GRANT SELECT ON VW_DOC_DETAIL_ACTIVE TO PROCEDURE PR_GET_DSC_RULES;
GRANT SELECT ON DSC_RULES TO PROCEDURE PR_GET_DSC_RULES;
/* Existing privileges on this procedure */
GRANT EXECUTE ON PROCEDURE PR_GET_DSC_RULES TO SYSDBA;
Создаем в кассире ТМС
uses
Graphics, Controls, Forms, Dialogs, StdCtrls,
ComCtrls, ExtCtrls, ibquery, DB, ChequeList, FR,
ScriptRes, Barcode,ZKassa, StrUtils, Windows, Classes,
IBDataBase, SysUtils, DateUtils, chequelist;
Procedure RecalcDSC(del:integer)
var iq: tibquery;
begin
Try
iq := tibquery.create(nil);
iq.transaction := CreateRT(CurrDB);
iq.transaction.starttransaction;
iq.active := False;
iq.sql.text := 'select * from PR_GET_DSC_RULES('+IntToStr(ChequeList.ActivePID)+','+IntToStr(ChequeList.Active.ID)+','+IntToStr(del)+')';
iq.active := True;
while not (iq.Eof) do
begin
ChequeList.Active.P_Index:= ChequeList.Active.IndexByPartID(iq.FieldByName('part_id_out').AsInteger);
if (iq.FieldByName('BARCODE_DSC').AsString = '') Then
ChequeList.Active.P_SetDiscount(-1*iq.FieldByName('DISCOUNT').AsFloat)
else
Barcode.ApplyDiscount(iq.FieldByName('BARCODE_DSC').AsString, iq.FieldByName('part_id_out').AsInteger);
iq.next;
End;
finally
iq.active := False;
iq.transaction.free;
iq.free;
end;
end;
Вызываем RecalcDSC в ТМС
-305 как RecalcDSC(0); -332 как RecalcDSC(1);
Скрипт должен выглядеть примерно так:
uses p10112u1; begin RecalcDSC(0); end;
Пример №2 (старый мех-м)
- акция действует всегда пока включен переключатель в параметрах системы
INSERT INTO PARAMS ( PARENT_ID, PARAM_ID, PARAM_CAPTION, PARAM_TYPE, PARAM_VALUE, AUDIT_ID, IMAGEINDEX, STATUS, INSERTDT, SORTING, PARAM_TYPE_DATA, PACKET) VALUES ( -30, 'AKCCII_TOGGLE', 'Включение акций', 14, '0', 3229, NULL, 0, '19-DEC-2015 10:45:34.828', NULL, 'FIXEDITEMS SHOWONLYVALUES RETURNNAME 0=выключено 1=включено');
- если переключатель включен - в кассире при продаже активируется скидка = разнице между заполненными колонками price и ещё одной ценовой колонкой, ниже использована PRICE_R
uses
Graphics, Controls, Forms, Dialogs, StdCtrls,
ComCtrls, ExtCtrls, ibquery, DB, ChequeList, FR,
ScriptRes, Barcode,ZKassa, StrUtils, Windows, Classes,
IBDataBase, SysUtils, DateUtils, chequelist;
var iq: tibquery;
dsc, part_id: integer;
discount: float;
begin
Try
iq := tibquery.create(nil);
iq.transaction := CreateRT(CurrDB);
iq.transaction.starttransaction;
iq.active := False;
iq.sql.text := 'select wb.part_id,wb.PRICE_R,(select p.param_value from params p where p.param_id = ''AKCCII_TOGGLE'') from vw_warebase wb where wb.part_id = '+
IntToStr(ChequeList.ActivePID);
iq.active := True;
if not(iq.Eof) then
if ( not iq.FieldByName('param_value').AsInteger=0 )then
if ( not iq.FieldByName('PRICE_R').isNull )then
if (iq.FieldByName('PRICE_R').AsFloat>0) then begin
ChequeList.Active.P_Index := ChequeList.Active.IndexByPartID(iq.FieldByName('part_id').AsInteger);
temp := -(ChequeList.Active.P_Price - iq.FieldByName('PRICE_R').AsFloat);
ChequeList.Active.P_SetDiscount(temp);
end;
finally
iq.active := False;
iq.transaction.free;
iq.free;
end;
Отправка ТМС по синхронизации
Выгружаем тмс из базы из blob поля в файл
Тмс можно найти спомощью запроса:
select * from groups g where g.id=-305
Затем сохраняем на жесткий диск тмс из поля data.
Загружаем ТМС в серверную базу
- В таблице g$profiles выбираем blob поле, которое будем использовать для отправки, например TMP_BLOB1.
- Убеждаемся, что данная таблица синхронизируется в двухстороннем направлении.
- Загружаем в это поле например первому профилю наш ТМС скрипт.
- Ждем когда это обновление придет всем по синхронизации.
Применяем всем ТМС
По g$tasks отправляем запрос нужным профилям:
update groups gp set gp.data = (select g.tmp_blob1 from G$PROFILES g where g.id = 1) where gp.id = -305;
Примеры акций
1. Акция на апрель, Эссенциале №30 - скидка 150 руб за каждую упаковку 2. Акция до конца мая, на Магне №50 (с ценой от 500 до 1000 руб) - при покупке 4х упаковок 1 в подарок; 3. Акция на Ферверкс, при покупке 2х упаковок 1 в подарок; 4. Аналогично Ферверксу, только на Маалокс; 5 и 6. На зодак №7 и №28 скидка 15%; 7. Акция на Эмолиум, при покупке 2х упаковок скидка 350 руб.; 8. Аналогично, на Фитолизин - 100 руб.; 9. На все ЖНВЛС скидка 5%; 10. На все товары с НДС опт. 10%, - скидка 10%; 11. На все товары с НДС опт. 18%, - скидка 15%;
- DATE_BEG и DATE_END - период действия скидки
- MMBSH1 - группа товара
- NDS_O1 - ставка НДС опт (10,18,12 ....)
- SNAME1 ... SNAME5 - слова, которым должна соответствовать позиция для того, чтобы скидка назначилась (все не обязательны)
- PRICE_MIN и PRICE_MAX - ценовой диапазон, которому должна соответствовать позиция, чтобы скидка назначилась (все не обязательны)
- QUANT_DIV и QUANT_DSC, для условий типа: при покупке 4х штук (QUANT_DIV) одна(QUANT_DSC) в подарок
- SUM_DSC - суммовая скидка на позицию в рублях
- PERC_DSC - процентная скидка на позицию в % (например 0.15)
- STATUS, 1 - правило активно, 0 - неактивно
