IP BomQty

Материал из iDempiere ru
Перейти к:навигация, поиск

Функции


iP_BomQty - это функция, которая раскладывает по уровням BOM и считает сколько нужно сырья на каждом уровне для получения конечного продукта в заданном количестве по нормам расходов. Расчет производится в точности до последних знаков после запятой как в Libero Manufacturing Order.

Изначально она была предназначена для сверки BOM с 1С при переходе.

На входе функции:
- готовый продукт или полуфабрикат,
- дата BOM(используется при хранении истории бомов, если истории не ведется, то можно любую дату),
- количество готового продукта или полуфабриката,
- последний параметр показывает нужно ли высчитывать сырье для полуфабрикатов с типом Компонент. 0 - не учитывать 'CO', 1 - учитывать 'CO'. (например, если есть полуфабрикаты фантомы, то для них нужно считать сырье, а если полуфабрикат изготавливается заранее и лежит уже готовый на складе, то считать на него сырье не нужно, достаточно показать сколько нужно этого полуфабриката для конечного продукта)

На выходе функции:
- конечный продукт,
- уровень BOM,
- полуфабрикат, изготавливаемый на уровне,
- необходимое количество этого полуфабриката на уровне для изготовления конечного продукта в заданном на входе количестве,
- ID строки BOM,
- сырье для изготовления полуфабриката на уровне,
- тип компонента,
- норма расхода,
- количество сырья, необходимое для изготовления полуфабриката на уровне в заданном количестве,

 
  CREATE OR REPLACE FUNCTION ip_bomqty(IN numeric, IN timestamp without time zone, IN numeric, IN numeric)
    RETURNS TABLE(sel_product_id numeric, 
                  levelno numeric, 
                  m_product_id numeric, 
                  bomqty numeric, 
                  pp_product_bomline_id numeric, 
                  m_productbom_id numeric, 
                  componenttype character, 
                  qtybom numeric, 
                  qtyrequired numeric) AS
  $BODY$
  
  /** @author @kinerix Anna Smirnova  */
  
  DECLARE L0 iP_BomQtyTypeCOPH[];
  DECLARE L1 iP_BomQtyTypeCOPH[];
  DECLARE L2 iP_BomQtyTypeCOPH[];
  DECLARE LNo numeric := 0;
  DECLARE Sel_Prod numeric := $1;
  DECLARE QtyReq numeric := $3;
  DECLARE P_date date := $2::date;
  DECLARE P_COPH numeric := $4;  /**when 0 then exclude raw from product with componenttype 'CO', because it is manufactured in other order*/
  
  BEGIN
  
  /**Before need to create custom type in this database*/
  /** create type iP_BomQtyTypeCOPH as (Sel_Product_ID numeric, 
  					LevelNo numeric, 
  					M_Product_ID numeric, 
  					BomQty numeric,
  					PP_Product_BomLine_ID numeric, 
  					M_ProductBom_ID numeric, 
  					ComponentType character(2),
  					QtyBom numeric, 
  					QtyRequired numeric);*/
  					
  L0 = (select  ARRAY[(select array_agg(array_to_string(ARRAY[(Sel_Prod, 
  							LNo, 
  							cast(0 as numeric), 
  							QtyReq,
  							cast(0 as numeric), 
  							Sel_Prod,
  							'',
  							cast(1 as numeric), 
  							QtyReq )]::iP_BomQtyTypeCOPH[], ', ')))]::iP_BomQtyTypeCOPH[]);
  L1 = L0;
  L2 = L0;
  
  LOOP
  
  L1 = (select 	ARRAY[(select array_agg(array_to_string(ARRAY[(
  				Sel_Prod,
  				LNo+1, 
  				t0.M_Product_ID, 
  				t2.QtyRequired,
  				t1.pp_product_bomline_ID,
  				t1.M_Product_ID,
  				t1.ComponentType,
  				t1.QtyBom,
  				cast(t1.QtyBom*t2.QtyRequired as numeric(19,5))
  				)]::iP_BomQtyTypeCOPH[], ', '))
  
  				
  				from pp_product_bomline t1
  				inner join pp_product_bom t0 on t1.pp_product_bom_ID = t0.pp_product_bom_ID 
  				inner join ( select * from unnest(L1) v0
  						where case when P_COPH=0 
  							then v0.ComponentType<>'CO' 
  							else v0.ComponentType=v0.ComponentType end ) t2 
  						on t2.M_ProductBom_ID = t0.M_Product_ID and t2.LevelNo = LNo
  				where	cast(t1.validfrom as date)<=P_date 
  					and (case when t1.validto is null then '2999-12-31' else cast(t1.validto as date) end)>=P_date
  				and t1.ComponentType <> 'VA'
  				and t0.m_product_ID in (select h.M_ProductBom_ID from unnest(L1) h where h.LevelNo = LNo)
  				 )]::iP_BomQtyTypeCOPH[]);
  
  LNo = LNo+1;
  
  L2 = 	(select		 	ARRAY[(select array_agg(array_to_string(ARRAY[(	L2_t.Sel_Product_ID, 
  										L2_t.LevelNo, 
  										L2_t.M_Product_ID, 
  										L2_t.BomQty, 
  										L2_t.PP_Product_BomLine_ID, 
  										L2_t.M_ProductBom_ID, 
  										L2_t.ComponentType,
  										L2_t.QtyBom, 
  										L2_t.QtyRequired)]::iP_BomQtyTypeCOPH[], ', '))
  	from
  	(select t0.Sel_Product_ID, t0.LevelNo, t0.M_Product_ID, t0.BomQty, t0.PP_Product_BomLine_ID,
                t0.M_ProductBom_ID, t0.ComponentType, t0.QtyBom, t0.QtyRequired from unnest(L2) t0
  	union all 
  	select t1.Sel_Product_ID, t1.LevelNo, t1.M_Product_ID, t1.BomQty, t1.PP_Product_BomLine_ID,
                t1.M_ProductBom_ID, t1.ComponentType, t1.QtyBom, t1.QtyRequired from unnest(L1) t1) L2_t  )]::iP_BomQtyTypeCOPH[]);
  
  EXIT WHEN LNo = 10;
  --- EXIT WHEN coalesce(L1,array[0]) = array[cast(0 as numeric)]; 
  --- EXIT WHEN coalesce((select count(*)::numeric from unnest(L1)),0) = cast(0 as numeric); 
  --- sometimes this exit from loop work's, sometimes - not. You can use HARD for levels of BOM for example LNo = 10 to exit from loop 100%
  
  END LOOP;
  	
  RETURN QUERY						
  
  select d.Sel_Product_ID, 
  	d.LevelNo, 
  	d.M_Product_ID, 
  	d.BomQty,
  	d.PP_Product_BomLine_ID, 
  	d.M_ProductBom_ID,
  	d.ComponentType, 
  	d.QtyBom, 
  	d.QtyRequired from unnest(L2) d;
  
  END;
  
  $BODY$
    LANGUAGE plpgsql VOLATILE
    COST 100
    ROWS 1000;
  ALTER FUNCTION ip_bomqty(numeric, timestamp without time zone, numeric, numeric)
    OWNER TO adempiere;
  
Cookie-файлы помогают нам предоставлять наши услуги. Используя наши сервисы, вы соглашаетесь с использованием cookie-файлов.