return: text
lang: plpgsql
src: |
  DECLARE	--eco.p_stock order by date_fin desc
  	result TEXT;
  BEGIN
  
  UPDATE eco.p_mouvements_articles
  	SET prix_unitaire_calcule = null;
  
  	-- initialisation des pump à première entrée ou au pu des stock selon le paramétrage
  	UPDATE eco.p_mouvements_articles
  	SET prix_unitaire_calcule = prix_unitaire
  	FROM (
  		SELECT
  			article_id,
  			site_id,
  			lieu_id,
  			(MIN(ARRAY[CASE WHEN entree_montant > 0 and entree_quantite > 0 THEN date::text ELSE '2099-12-31' END, oid::text]))[2] as oid
  		FROM eco.p_mouvements_articles
  		LEFT JOIN eco.t_divers ON t_divers.code = 'FORCE_PUMP_STOCK'
  		WHERE t_divers.valeur = '0'
  		GROUP BY 1,2,3
  		) sub
  	WHERE p_mouvements_articles.oid = sub.oid
  		AND  p_mouvements_articles.site_id = sub.site_id
  		AND  p_mouvements_articles.lieu_id = sub.lieu_id
  		AND  p_mouvements_articles.article_id = sub.article_id
  		;
  		
  	UPDATE eco.p_mouvements_articles
  	SET prix_unitaire_calcule = CASE WHEN pump_ttc > 0 THEN pump_ttc ELSE pump END
  	FROM (
  		SELECT
  			article_id,
  			site_id,
  			lieu_id,
  			date_fin,
  			pump,
  			pump_ttc
  		FROM eco.p_stock
  		LEFT JOIN eco.t_divers ON t_divers.code = 'FORCE_PUMP_STOCK'
  		WHERE t_divers.valeur = '1'
  		) sub
  	WHERE (p_mouvements_articles.lieu_id = sub.lieu_id OR (SELECT COUNT(DISTINCT lieu_id) FROM eco.p_stock) = 1)
  		AND  p_mouvements_articles.site_id = sub.site_id
  		AND  p_mouvements_articles.article_id = sub.article_id
  		AND sub.date_fin BETWEEN date AND p_mouvements_articles.date_fin
  	;
  	
  	-- ou si le stock est nul avant et pas après
  	UPDATE eco.p_mouvements_articles
  	SET prix_unitaire_calcule = prix_unitaire
  	WHERE prix_unitaire_calcule IS NULL 
  	AND stock_quantite_debut <= 0
  	AND stock_quantite_fin > 0;
  	
  	-- pump 0 si pas de stock
  	UPDATE eco.p_mouvements_articles
  	SET prix_unitaire_calcule = 0
  	WHERE stock_quantite_fin = 0
  	;
  
  	ANALYSE eco.p_mouvements_articles;
  
  	DROP SEQUENCE IF EXISTS s_mv_sto;
  	CREATE TEMP SEQUENCE s_mv_sto; 
  
  	DROP TABLE IF EXISTS w_mvt_sto;
  	CREATE TEMP TABLE w_mvt_sto AS
  	SELECT
  		nextval(' s_mv_sto'::regclass) AS sequence,
  		*,
  		0::bigint AS derniere_entree
  		FROM (
  			SELECT article_id,
  			site_id,
  			lieu_id,
  			date,
  			oid,
  			stock_quantite_fin,
  			entree_quantite,
  			entree_montant,
  			prix_unitaire_calcule,
  			date_fin
  		FROM eco.p_mouvements_articles
  		WHERE date >= date_trunc('month', now()) - interval '3 year'
  		ORDER BY 1,2,3,4,5
  		) sub;
  
  	-- sélection des mouvements d'entrée
  	DROP TABLE IF EXISTS w_periode_sto;
  	CREATE TEMP TABLE w_periode_sto AS 
  			SELECT article_id,
  			site_id,
  			lieu_id,
  			date,
  			oid,
  			lead(oid,1) OVER (PARTITION BY article_id, site_id, lieu_id ORDER BY sequence) AS oid_next,
  			lead(date,1) OVER (PARTITION BY article_id, site_id, lieu_id ORDER BY sequence) as date_fin
  			FROM w_mvt_sto
  			WHERE (entree_montant > 0 AND entree_quantite > 0)
  			ORDER BY 1,2,3,4
  	;
  
  	UPDATE w_periode_sto SET date_fin = '2099-12-31' WHERE date_fin IS NULL;
  
  	-- calcul des dernière entrées
  	UPDATE w_mvt_sto 
  	SET derniere_entree = w_periode_sto.oid
  	FROM w_periode_sto
  	WHERE 1=1 
  		AND w_mvt_sto.article_id = w_periode_sto.article_id
  		AND w_mvt_sto.site_id = w_periode_sto.site_id
  		AND w_mvt_sto.lieu_id = w_periode_sto.lieu_id
  		AND (w_mvt_sto.oid = w_periode_sto.oid_next
  		OR (w_mvt_sto.oid > w_periode_sto.oid AND w_mvt_sto.date BETWEEN w_periode_sto.date AND w_periode_sto.date_fin))
  		;
  
  	UPDATE w_mvt_sto 
  	SET derniere_entree = w_first_ent.oid
  	FROM (SELECT article_id, site_id, lieu_id, (MIN(ARRAY[date::text, oid::text]))[2]::bigint as oid FROM w_periode_sto GROUP BY 1,2,3) w_first_ent
  	WHERE 1=1 
  		AND derniere_entree = 0
  		AND w_mvt_sto.article_id = w_first_ent.article_id
  		AND w_mvt_sto.site_id = w_first_ent.site_id
  		AND w_mvt_sto.lieu_id = w_first_ent.lieu_id
  		;
  
  
  	CREATE INDEX w_mvt_article_id ON w_mvt_sto USING btree (article_id);
  	CREATE INDEX w_mvt_site_id ON w_mvt_sto USING btree (site_id);
  	CREATE INDEX w_mvt_lieu_id ON w_mvt_sto USING btree (lieu_id);
  	CREATE INDEX w_mvt_oid ON w_mvt_sto USING btree (oid);
  
  	ANALYSE w_mvt_sto;
  
  	-- maj des pump
  	PERFORM base.cti_execute('
  
  	UPDATE w_mvt_sto
  	SET prix_unitaire_calcule = base.cti_division(abs(w_mvt_prev.stock_quantite_fin)*w_mvt_prev.prix_unitaire_calcule + abs(w_mvt_sto.entree_montant), abs(w_mvt_prev.stock_quantite_fin) +  abs(w_mvt_sto.entree_quantite))
  	FROM w_mvt_sto w_mvt_prev
  	WHERE 1=1 
  		AND w_mvt_sto.prix_unitaire_calcule IS NULL
  		AND w_mvt_prev.prix_unitaire_calcule IS NOT NULL
  		AND w_mvt_sto.derniere_entree = w_mvt_prev.oid
  		AND (w_mvt_sto.entree_montant != 0)',2000)
  		--select article_id, lieu_id, (MIN(ARRAY[sequence::text, prix_unitaire_calcule::text]))[2] from w_mvt_sto group by 1,2 having (MIN(ARRAY[sequence::text, prix_unitaire_calcule::text]))[2] is null order by 3 desc
  		--select * from eco.v_mouvements_articles_1 where article_id = 6634 and lieu_id = 2 order by date
  		--select * from w_mvt_sto where article_id = 9663 and lieu_id = 2 order by sequence
  ;		
  	-- extension aux mouvements de sortie
  	UPDATE w_mvt_sto
  	SET prix_unitaire_calcule = w_mvt_prev.prix_unitaire_calcule
  	FROM w_mvt_sto w_mvt_prev 
  	WHERE 1=1 
  	AND w_mvt_sto.prix_unitaire_calcule IS NULL 
  	AND w_mvt_sto.derniere_entree != 0
  	AND w_mvt_prev.oid = w_mvt_sto.derniere_entree
  	AND w_mvt_prev.prix_unitaire_calcule IS NOT NULL 
  	;
  
  	-- prise en compte des lieu différents au besoin
  	UPDATE w_mvt_sto
  	SET prix_unitaire_calcule = w_mvt_prev.prix_unitaire_calcule
  	FROM w_mvt_sto w_mvt_prev 
  	WHERE 1=1 
  	AND w_mvt_sto.prix_unitaire_calcule IS NULL 
  	AND w_mvt_prev.article_id = w_mvt_sto.article_id
  	AND w_mvt_prev.prix_unitaire_calcule IS NOT NULL
  	AND w_mvt_sto.date BETWEEN w_mvt_prev.date AND w_mvt_prev.date_fin
  	AND w_mvt_prev.site_id != w_mvt_sto.site_id
  	AND w_mvt_prev.lieu_id != w_mvt_sto.lieu_id
  	;
  
  	-- maj des mouvements
  	UPDATE eco.p_mouvements_articles 
  	SET prix_unitaire_calcule = round(w_mvt_sto.prix_unitaire_calcule,10)
  	FROM w_mvt_sto
  	WHERE p_mouvements_articles.oid = w_mvt_sto.oid
  	;
  
  	-- sinon (au pire si pas d'information) pump = pu
  	UPDATE eco.p_mouvements_articles 
  	SET prix_unitaire_calcule = prix_unitaire
  	WHERE 1=1 
  	AND prix_unitaire_calcule IS NULL
  	;
  
  	
  	RETURN 'OK';
  END;