unit ModuleLogistique_RechercheClasses; interface uses System.SysUtils, System.Classes, Data.DB, xxxx.DB, xxxx.DB.Entity, xxxx.Entity.Colis, xxxx.Business.Colis, ModuleLogistique_Classes, ModuleLogistique_ReceptionClasses; type { Forward class declarations } TModuleLogistiqueRechercheColis = class; /// Erreur de base liée à la reception de colis EModuleLogistiqueRechercheColisError = class(Exception); /// Moteur de gestion de reception de colis TModuleLogistiqueRechercheColis = class(TObject) public // Constantes publiques const COL_NATURE_COLIS_LIB_ALIAS = 'F_NATURE_LIB'; COL_MAG_SRC_ALIAS = 'F_SOURCE'; COL_MAG_DEST_ALIAS = 'F_DESTINATION'; COL_MAG_RECEPT_ALIAS = 'F_RECEPTION'; COL_HIGHLIGHT_ALIAS = 'F_HIGHLIGHT'; COL_TRANSPORT_ALIAS = 'F_TRANSPORTEUR'; // Types publiques type TSearchType = (stNone, stPick, stColisXYZ, stDate); TSearchDateType = (sdtNone, sdtPreReception, sdtOuverture, sdtReceptionColis, sdtRemiseTransporteur); TSearchString = string[15]; // 9 + 5 Zéros pour un colis scanné, 12 + 1 Zéro pour un bordereau scanné TSearchCriteria = record public class function Create(ASearchType: TSearchType; const ANumero: string): TSearchCriteria; overload; static; class function Create(ASearchDateType: TSearchDateType; ADate: TDate): TSearchCriteria; overload; static; public MagasinOrigine: string; MagasinDestination: string; MagasinReception: string; case SearchType: TSearchType of stPick: (NumeroBordereau: TSearchString); stColisXYZ: (NumeroColis: TSearchString); stDate: (DateValue: TDate; DateType: TSearchDateType); end; private // Membres privés - Entrée\Sortie FSearchResult: TxxxxDBQuery; FExpeditionColis: TxxxxEntityExpeditionColis; FColis: TxxxxEntityColis; FSearchCriteria: TSearchCriteria; FLastSearchCriteria: TSearchCriteria; // Méthodes privées procedure MakeSearchQuery(ASearchCriteria: TSearchCriteria); function LoadBordereauQuery(): TxxxxDBQuery; function LoadColisQuery(): TxxxxDBQuery; procedure CriteriaToParam(AQuery: TxxxxDBQuery); function NearSearch(ACriteriaOne, ACriteriaTwo: TSearchCriteria): Boolean; // Accesseurs function GetColisDuBorderau(): TxxxxEntityColis; function GetExpeditionColis(): TxxxxEntityExpeditionColis; public // Constructeurs d'Instance destructor Destroy(); override; // Méthodes publiques function Search(ASearchCriteria: TSearchCriteria): Boolean; procedure ScrollColisOfBordereau(); procedure ScrollBordereauOfColis(); function IsScrolledBordereauAndColis(): Boolean; // Propriétés - Entrée\Sortie property ExpeditionColis: TxxxxEntityExpeditionColis read GetExpeditionColis; property ColisDuBorderau: TxxxxEntityColis read GetColisDuBorderau; end; implementation uses System.DateUtils; { TModuleLogistiqueRechercheColis } //------------------------------------------------------------------------------ procedure TModuleLogistiqueRechercheColis.CriteriaToParam(AQuery: TxxxxDBQuery); begin if FSearchCriteria.SearchType = stPick then AQuery.ParamByName('pAWB').Value := FSearchCriteria.NumeroBordereau; if (FSearchCriteria.SearchType = stDate) and (FSearchCriteria.DateType = sdtPreReception) then AQuery.ParamByName('pDatePreReception').Value := DateOf(FSearchCriteria.DateValue); if (FSearchCriteria.SearchType = stDate) and (FSearchCriteria.DateType = sdtOuverture) then AQuery.ParamByName('pDateOuverture').Value := DateOf(FSearchCriteria.DateValue); if FSearchCriteria.SearchType = stColisXYZ then AQuery.ParamByName('pNumColisXYZ').Value := FSearchCriteria.NumeroColis; if (FSearchCriteria.SearchType = stDate) and (FSearchCriteria.DateType = sdtReceptionColis) then AQuery.ParamByName('pDateReception').Value := DateOf(FSearchCriteria.DateValue); if (FSearchCriteria.SearchType = stDate) and (FSearchCriteria.DateType = sdtRemiseTransporteur) then AQuery.ParamByName('pDateTransporteur').Value := DateOf(FSearchCriteria.DateValue); if FSearchCriteria.MagasinOrigine <> '' then AQuery.ParamByName('pMagasinOrigine').Value := FSearchCriteria.MagasinOrigine; if FSearchCriteria.MagasinDestination <> '' then AQuery.ParamByName('pMagasinDestination').Value := FSearchCriteria.MagasinDestination; if (FSearchCriteria.SearchType <> stColisXYZ) and (FSearchCriteria.MagasinReception <> '') then AQuery.ParamByName('pMagasinReception').Value := FSearchCriteria.MagasinReception; end; //------------------------------------------------------------------------------ destructor TModuleLogistiqueRechercheColis.Destroy(); begin FreeAndNil(FSearchResult); FreeAndNil(FExpeditionColis); FreeAndNil(FColis); inherited Destroy(); end; //------------------------------------------------------------------------------ function TModuleLogistiqueRechercheColis.GetColisDuBorderau(): TxxxxEntityColis; begin if Assigned(FSearchResult) then begin if not Assigned(FColis) then begin FColis := TxxxxEntityColis.CreateAsSet(nil); FColis.ReadOnly := True; FColis.OwnsQuery := True; end; if not Assigned(FColis.Query) then FColis.Query := LoadColisQuery(); Result := FColis; end else raise EModuleLogistiqueRechercheColisError.Create('Pas de recherche active'); end; //------------------------------------------------------------------------------ function TModuleLogistiqueRechercheColis.GetExpeditionColis(): TxxxxEntityExpeditionColis; begin if Assigned(FSearchResult) then begin if not Assigned(FExpeditionColis) then begin FExpeditionColis := TxxxxEntityExpeditionColis.CreateAsSet(nil); FExpeditionColis.ReadOnly := True; FExpeditionColis.OwnsQuery := True; end; if not Assigned(FExpeditionColis.Query) then FExpeditionColis.Query := LoadBordereauQuery(); Result := FExpeditionColis; end else raise EModuleLogistiqueRechercheColisError.Create('Pas de recherche active'); end; //------------------------------------------------------------------------------ function TModuleLogistiqueRechercheColis.IsScrolledBordereauAndColis(): Boolean; begin if Assigned(FExpeditionColis) and Assigned(FColis) and Assigned(FExpeditionColis.DataSet) and Assigned(FColis.DataSet) and not FExpeditionColis.DataSet.ControlsDisabled and not FColis.DataSet.ControlsDisabled then Result := FColis.DataSet.FieldByName('EXP_N_ID').AsFloat = FExpeditionColis.DataSet.FieldByName('EXP_N_ID').AsFloat else Result := False; end; //------------------------------------------------------------------------------ function TModuleLogistiqueRechercheColis.LoadBordereauQuery(): TxxxxDBQuery; const SQL_SELECT_CLAUSE_FIELDS = '[SelectClauseFields]'; SQL_SELECT_BASE = ' SELECT ' + SQL_SELECT_CLAUSE_FIELDS + ', ' + ' ms.MAG_CH_NOM AS ' + COL_MAG_SRC_ALIAS + ', ' + ' md.MAG_CH_NOM AS ' + COL_MAG_DEST_ALIAS + ', ' + ' mr.MAG_CH_NOM AS ' + COL_MAG_RECEPT_ALIAS + ', ' + ' trp.TRP_CH_LIBELLE AS ' + COL_TRANSPORT_ALIAS + ', ' + ' CASE WHEN (:pAWB IS NOT NULL AND ec.EXP_CH_AWB = :pAWB) ' + ' OR (:pDatePreReception IS NOT NULL AND TRUNC(ec.EXP_DT_RECEPTION) = :pDatePreReception) ' + ' OR (:pDateOuverture IS NOT NULL AND TRUNC(ec.EXP_DT_OUVERTURE) = :pDateOuverture) THEN 1 ELSE 0 END AS ' + COL_HIGHLIGHT_ALIAS + ' FROM T_EXPEDITIONCOLIS ec ' + ' LEFT JOIN T_MAGASINXY ms ON ms.MAG_CH_CODE = ec.MAG_CH_SRC ' + ' LEFT JOIN T_MAGASINXY md ON md.MAG_CH_CODE = ec.MAG_CH_DST ' + ' LEFT JOIN T_MAGASINXY mr ON mr.MAG_CH_CODE = ec.EXP_CH_MAG_RECEPT ' + ' LEFT JOIN T_TRANSPORTEUR trp ON trp.TRP_N_TRANSPORT = ec.TRP_N_TRANSPORT ' ; SQL_SELECT_WHERE = ' WHERE ec.EXP_N_ID IN (%s) ' ; SQL_SELECT_ORDER = ' ORDER BY ec.EXP_CH_AWB ' ; var SQL: string; begin SQL := SQL_SELECT_BASE; SQL := StringReplace(SQL, SQL_SELECT_CLAUSE_FIELDS, TxxxxBusinessExpeditionColis.MakeSQLSelectClauseFields(TxxxxBusinessExpeditionColis.xxxxEntity, 'ec'), []) + Format(SQL_SELECT_WHERE, [FSearchResult.SQLText]) + SQL_SELECT_ORDER; Result := TxxxxDBQuery.Create(TModuleLogistique.Instance.DBConnection); try Result.SQLText := SQL; CriteriaToParam(Result); Result.Open(); except on E: Exception do FreeAndNil(Result); end; end; //------------------------------------------------------------------------------ function TModuleLogistiqueRechercheColis.LoadColisQuery(): TxxxxDBQuery; const SQL_JOIN_TYPE_EXPEDITION = '[JoinTypeExpedition]'; SQL_SELECT_CLAUSE_FIELDS = '[SelectClauseFields]'; SQL_SELECT_BASE = ' SELECT ec.EXP_N_ID, ' + SQL_SELECT_CLAUSE_FIELDS + ', ' + ' ms.MAG_CH_NOM AS ' + COL_MAG_SRC_ALIAS + ', ' + ' md.MAG_CH_NOM AS ' + COL_MAG_DEST_ALIAS + ', ' + ' ctpnc.NAT_CH_LIBELLE AS ' + COL_NATURE_COLIS_LIB_ALIAS + ', ' + ' CASE WHEN (:pNumColisXYZ IS NOT NULL AND c.COL_N_NUMCOLIS = :pNumColisXYZ) ' + ' OR (:pDateReception IS NOT NULL AND TRUNC(c.COL_DT_RECEPTION) = :pDateReception) THEN 1 ELSE 0 END AS ' + COL_HIGHLIGHT_ALIAS + ' FROM T_EXPEDITIONCOLIS ec ' ' INNER JOIN T_COLIS_EXPEDIE ce ON ce.EXP_N_ID = ec.EXP_N_ID ' + SQL_JOIN_TYPE_EXPEDITION + ' JOIN T_COLIS c ON c.COL_N_NUMCOLIS = ce.COL_N_NUMCOLIS ' + ' LEFT JOIN TP_ETATCOLIS ctpec ON ctpec.COL_C_ETATCOLIS = c.COL_C_ETATCOLIS ' + ' LEFT JOIN TP_TYPECOLIS ctptc ON ctptc.COL_C_TYPE = c.COL_C_TYPE ' + ' LEFT JOIN TP_NATURECOLIS ctpnc ON ctpnc.COL_N_NATURE = c.COL_N_NATURE ' + ' LEFT JOIN T_MAGASINXY ms ON ms.MAG_CH_CODE = c.MAG_CH_CODE_DEPART ' + ' LEFT JOIN T_MAGASINXY md ON md.MAG_CH_CODE = c.MAG_CH_CODE ' ; SQL_SELECT_WHERE = ' WHERE ec.EXP_N_ID IN (%s) ' ; SQL_SELECT_WHERE_COLIS = ' WHERE c.COL_N_NUMCOLIS = :pNumColisXYZ ' ; SQL_SELECT_ORDER = ' ORDER BY ec.EXP_CH_AWB ' ; var SQL, ClauseWhere: string; ExpeditionJoinType: string; begin SQL := SQL_SELECT_BASE if FSearchCriteria.SearchType = stColisXYZ then begin ExpeditionJoinType := 'RIGHT OUTER'; ClauseWhere := SQL_SELECT_WHERE_COLIS; end else begin ExpeditionJoinType := 'INNER'; ClauseWhere := Format(SQL_SELECT_WHERE, [FSearchResult.SQLText]); end; SQL := StringReplace(SQL, SQL_JOIN_TYPE_EXPEDITION, ExpeditionJoinType, []); SQL := StringReplace(SQL, SQL_SELECT_CLAUSE_FIELDS, TxxxxBusinessColis.MakeSQLSelectClauseFields(TxxxxBusinessColis.xxxxEntity, 'c'), []) + ClauseWhere + SQL_SELECT_ORDER; Result := TxxxxDBQuery.Create(TModuleLogistique.Instance.DBConnection); try Result.SQLText := SQL; CriteriaToParam(Result); Result.Open(); except on E: Exception do FreeAndNil(Result); end; end; //------------------------------------------------------------------------------ procedure TModuleLogistiqueRechercheColis.MakeSearchQuery(ASearchCriteria: TSearchCriteria); const SQL_JOIN_TYPE_EXPEDITION = '[JoinTypeExpedition]'; SQL_SELECT_BASE = ' SELECT s_ec.EXP_N_ID ' + ' FROM T_EXPEDITIONCOLIS s_ec ' + ' INNER JOIN T_COLIS_EXPEDIE s_ce ON s_ce.EXP_N_ID = s_ec.EXP_N_ID ' + SQL_JOIN_TYPE_EXPEDITION + ' JOIN T_COLIS s_c ON s_c.COL_N_NUMCOLIS = s_ce.COL_N_NUMCOLIS ' ; // UPPER = INSENSITIVE CASE : NLS_COMP en LINGUISTIC est trop risqué car impacte toute la session ! SQL_WHERE_NUMEROS: array[stNone..stColisXYZ] of string = ( ' WHERE 1 = 1 ', ' WHERE UPPER(s_ec.EXP_CH_AWB) = UPPER(:pAWB) ' , ' WHERE s_c.COL_N_NUMCOLIS = :pNumColisXYZ ' ); SQL_WHERE_DATES: array[Succ(Low(TSearchDateType))..High(TSearchDateType)] of string = ( ' WHERE TRUNC(s_ec.EXP_DT_RECEPTION) = :pDatePreReception ' , ' WHERE TRUNC(s_ec.EXP_DT_OUVERTURE) = :pDateOuverture ' , ' WHERE TRUNC(s_c.COL_DT_RECEPTION) = :pDateReception ', ' WHERE TRUNC(s_ec.EXP_DT_REMISETRP) = :pDateTransporteur ' ); SQL_FILTER_SRC = ' AND ( s_ec.MAG_CH_SRC = :pMagasinOrigine OR s_c.MAG_CH_CODE_DEPART = :pMagasinOrigine ) ' ; SQL_FILTER_DST = ' AND ( s_ec.MAG_CH_DST = :pMagasinDestination OR s_c.MAG_CH_CODE = :pMagasinDestination ) ' ; SQL_FILTER_RECEPT = ' AND ( s_ec.EXP_CH_MAG_RECEPT = :pMagasinReception ) ' ; var SQL: string; ExpeditionJoinType: string; begin FSearchCriteria := ASearchCriteria; if not NearSearch(FSearchCriteria, FLastSearchCriteria) then FreeAndNil(FSearchResult); if not Assigned(FSearchResult) then begin FSearchResult := TxxxxDBQuery.Create(TModuleLogistique.Instance.DBConnection); SQL := SQL_SELECT_BASE if FSearchCriteria.SearchType = stColisXYZ then ExpeditionJoinType := 'RIGHT OUTER' else ExpeditionJoinType := 'INNER'; SQL := StringReplace(SQL, SQL_JOIN_TYPE_EXPEDITION, ExpeditionJoinType, []); if FSearchCriteria.SearchType = stDate then begin if FSearchCriteria.DateType in [Low(SQL_WHERE_DATES)..High(SQL_WHERE_DATES)] then begin SQL := SQL + SQL_WHERE_DATES[FSearchCriteria.DateType]; end else raise EModuleLogistiqueRechercheColisError.Create('Type de recherche avec date inconnu'); end else begin if FSearchCriteria.SearchType in [Low(SQL_WHERE_NUMEROS)..High(SQL_WHERE_NUMEROS)] then SQL := SQL + SQL_WHERE_NUMEROS[FSearchCriteria.SearchType] else raise EModuleLogistiqueRechercheColisError.Create('Type de recherche inconnu'); end; if FSearchCriteria.MagasinOrigine <> '' then SQL := SQL + SQL_FILTER_SRC; if FSearchCriteria.MagasinDestination <> '' then SQL := SQL + SQL_FILTER_DST; if (FSearchCriteria.SearchType <> stColisXYZ) and (FSearchCriteria.MagasinReception <> '') then SQL := SQL + SQL_FILTER_RECEPT; FSearchResult.SQLText := SQL; FSearchResult.Prepared := True; end else FSearchResult.Close(); try CriteriaToParam(FSearchResult); FSearchResult.Open(); FLastSearchCriteria := FSearchCriteria; except on E: Exception do begin FreeAndNil(FSearchResult); FLastSearchCriteria.SearchType := stNone; end; end; end; //------------------------------------------------------------------------------ function TModuleLogistiqueRechercheColis.NearSearch(ACriteriaOne, ACriteriaTwo: TSearchCriteria): Boolean; begin Result := False; if ACriteriaOne.SearchType = ACriteriaTwo.SearchType then begin if (ACriteriaOne.SearchType = stDate) and (ACriteriaOne.DateType <> ACriteriaTwo.DateType) then Exit; if ACriteriaOne.MagasinOrigine <> ACriteriaTwo.MagasinOrigine then Exit; if ACriteriaOne.MagasinDestination <> ACriteriaTwo.MagasinDestination then Exit; if ACriteriaOne.MagasinReception <> ACriteriaTwo.MagasinReception then Exit; Result := True; end; end; //------------------------------------------------------------------------------ procedure TModuleLogistiqueRechercheColis.ScrollBordereauOfColis(); begin if Assigned(FExpeditionColis) and Assigned(FColis) and Assigned(FExpeditionColis.DataSet) and Assigned(FColis.DataSet) and not FExpeditionColis.DataSet.ControlsDisabled and not FColis.DataSet.ControlsDisabled then FExpeditionColis.DataSet.Locate('EXP_N_ID', FColis.DataSet.FieldByName('EXP_N_ID').AsFloat, []); end; //------------------------------------------------------------------------------ procedure TModuleLogistiqueRechercheColis.ScrollColisOfBordereau(); begin if Assigned(FExpeditionColis) and Assigned(FColis) and Assigned(FExpeditionColis.DataSet) and Assigned(FColis.DataSet) and not FExpeditionColis.DataSet.ControlsDisabled and not FColis.DataSet.ControlsDisabled then FColis.DataSet.Locate('EXP_N_ID', FExpeditionColis.DataSet.FieldByName('EXP_N_ID').AsFloat, []); end; //------------------------------------------------------------------------------ function TModuleLogistiqueRechercheColis.Search(ASearchCriteria: TSearchCriteria): Boolean; begin if Assigned(FExpeditionColis) then FExpeditionColis.Query := nil; if Assigned(FColis) then FColis.Query := nil; MakeSearchQuery(ASearchCriteria); Result := Assigned(FSearchResult) and not FSearchResult.IsEmpty(); end; { TModuleLogistiqueRechercheColis.TSearchCriteria } //------------------------------------------------------------------------------ class function TModuleLogistiqueRechercheColis.TSearchCriteria.Create(ASearchType: TSearchType; const ANumero: string): TSearchCriteria; begin Result.SearchType := ASearchType; case ASearchType of stPick : Result.NumeroBordereau := TSearchString(ANumero); stColisXYZ : Result.NumeroColis := TSearchString(ANumero); end; end; //------------------------------------------------------------------------------ class function TModuleLogistiqueRechercheColis.TSearchCriteria.Create(ASearchDateType: TSearchDateType; ADate: TDate): TSearchCriteria; begin Result.SearchType := stDate; Result.DateType := ASearchDateType; Result.DateValue := ADate; end; end.