unit rmBGLExecutionDm;

interface

uses
  SysUtils, Classes, ProjectData, DB, DBClient, sdIDTree, sdDB;

type
  TGclNode = class
  private
    FQuantity: Double;
    FTotalPrice: Double;
    FPrice: Double;
    FUnits: string;
    FName: string;
    FB_Code: string;
  public
    property B_Code: string read FB_Code write FB_Code;
    property Name: string read FName write FName;
    property Units: string read FUnits write FUnits;
    property Price: Double read FPrice write FPrice;
    property Quantity: Double read FQuantity write FQuantity;
    property TotalPrice: Double read FTotalPrice write FTotalPrice;
  end;

  TXmjNode = class
  private
    FCode: string;
    FName: string;
    FUnits: string;
    FGclList: TList;
  public
    constructor Create;
    destructor Destroy; override;

    function AddGclNode(AB_Code: string): TGclNode;

    property Code: string read FCode write FCode;
    property Name: string read FName write FName;
    property Units: string read FUnits write FUnits;
    property GclList: TList read FGclList;
  end;

  TBGLNode = class
  private
    FBGLCode: string;
    FXmjList: TList;
  public
    constructor Create;
    destructor Destroy; override;

    function FindXmjNode(ACode: string): TXmjNode;
    function AddXmjNode(ACode: string): TXmjNode;

    property BGLCode: string read FBGLCode write FBGLCode;
    property XmjList: TList read FXmjList;
  end;

  TrmBGLExecutionData = class(TDataModule)
    cdsBGLExecution: TClientDataSet;
    cdsBGLExecutionBGLCode: TWideStringField;
    cdsBGLExecutionCode: TStringField;
    cdsBGLExecutionB_Code: TStringField;
    cdsBGLExecutionName: TWideStringField;
    cdsBGLExecutionUnits: TWideStringField;
    cdsBGLExecutionPrice: TFloatField;
    cdsBGLExecutionQuantity: TFloatField;
    cdsBGLExecutionTotalPrice: TFloatField;
  private
    FProjectData: TProjectData;
    FBGLList: TList;

    function FindBGLNode(ABGLCode: string): TBGLNode;
    function AddBGLNode(ABGLCode: string): TBGLNode;

    procedure FilterGclBills(ANode: TsdIDTreeNode);
    procedure FilterBills(ANode: TsdIDTreeNode);

    procedure WriteData;
  public
    function AssignData(AProjectData: TProjectData): TDataSet;
  end;

implementation

uses
  ZhAPI, UtilMethods, PhaseData, BillsCompileDm;

{$R *.dfm}

{ TrmBGLExecutionData }

function TrmBGLExecutionData.AddBGLNode(ABGLCode: string): TBGLNode;
var
  Node: TBGLNode;
  i, iIndex: Integer;
begin
  // 新增
  Result := TBGLNode.Create;
  Result.BGLCode := ABGLCode;
  // List中根据顺序新增
  iIndex := FBGLList.Count;
  for i := 0 to FBGLList.Count - 1 do
  begin
    Node := TBGLNode(FBGLList.Items[i]);
    if ABGLCode < Node.BGLCode then
    begin
      iIndex := i;
      Break;
    end;
  end;
  FBGLList.Insert(iIndex, Result);
end;

function TrmBGLExecutionData.AssignData(
  AProjectData: TProjectData): TDataSet;
begin
  cdsBGLExecution.DisableControls;
  cdsBGLExecution.Active := True;
  cdsBGLExecution.EmptyDataSet;
  FBGLList := TList.Create;
  try
    FProjectData := AProjectData;
    FilterBills(AProjectData.BillsMeasureData.BillsMeasureTree.FirstNode);
    WriteData;
    Result := cdsBGLExecution;
  finally
    ClearObjects(FBGLList);
    FBGLList.Free;
    cdsBGLExecution.EnableControls;
  end;
end;

procedure TrmBGLExecutionData.FilterBills(ANode: TsdIDTreeNode);
begin
  if not Assigned(ANode) then Exit;
  if not ANode.HasChildren then
    FilterGclBills(ANode);
  FilterBills(ANode.FirstChild);
  FilterBills(ANode.NextSibling);
end;

procedure TrmBGLExecutionData.FilterGclBills(ANode: TsdIDTreeNode);

  procedure AddBGLData(ABGLCode, ABGLNum: string);
  var
    BGLNode: TBGLNode;
    XmjNode: TXmjNode;
    GclNode: TGclNode;
    LeafXmjParent: TsdIDTreeNode;
  begin
    // BGL
    BGLNode := FindBGLNode(ABGLCode);
    if not Assigned(BGLNode) then
      BGLNode := AddBGLNode(ABGLCode);
    // Xmj
    with FProjectData.BillsCompileData do
      LeafXmjParent := BillsCompileTree.FindNode(GetLeafXmjParentID(ANode.ID));
    XmjNode := BGLNode.FindXmjNode(LeafXmjParent.Rec.ValueByName('Code').AsString);
    if not Assigned(XmjNode) then
      XmjNode := BGLNode.AddXmjNode(LeafXmjParent.Rec.ValueByName('Code').AsString);
    XmjNode.Name := LeafXmjParent.Rec.ValueByName('Name').AsString;
    XmjNode.Units := LeafXmjParent.Rec.ValueByName('Units').AsString;    
    // Gcl
    GclNode := XmjNode.AddGclNode(ANode.Rec.ValueByName('B_Code').AsString);
    GclNode.Name := ANode.Rec.ValueByName('Name').AsString;
    GclNode.FUnits := ANode.Rec.ValueByName('Units').AsString;
    GclNode.Price := ANode.Rec.ValueByName('Price').AsFloat;
    GclNode.Quantity := StrToFloatDef(ABGLNum, 0);
    GclNode.TotalPrice := GclNode.Quantity * GclNode.Price;
  end;

var
  StageRec: TsdDataRecord;
  sgsCode, sgsNum: TStringList;
  i: Integer;
begin
  StageRec := FProjectData.PhaseData.StageData.StageRecord(ANode.ID);
  if (ANode.Rec.ValueByName('B_Code').AsString = '') or
      (not Assigned(StageRec)) or
      (StageRec.ValueByName('QcBGLCode').AsString = '') then Exit;
  sgsCode := TStringList.Create;
  sgsNum := TStringList.Create;
  try
    sgsCode.Delimiter := ';';
    sgsCode.DelimitedText := StageRec.ValueByName('QcBGLCode').AsString;
    sgsNum.Delimiter := ';';
    sgsNum.DelimitedText := StageRec.ValueByName('QcBGLNum').AsString;
    for i := 0 to sgsCode.Count - 1 do
      AddBGLData(sgsCode[i], sgsNum[i]);
  finally
    sgsNum.Free;
    sgsCode.Free;
  end;
end;

function TrmBGLExecutionData.FindBGLNode(ABGLCode: string): TBGLNode;
var
  iBGL: Integer;
  BGLNode: TBGLNode;
begin
  Result := nil;
  for iBGL := 0 to FBGLList.Count - 1 do
  begin
    BGLNode := TBGLNode(FBGLList.Items[iBGL]);
    if SameText(BGLNode.BGLCode, ABGLCode) then
    begin
      Result := BGLNode;
      Break;
    end;
  end;
end;

procedure TrmBGLExecutionData.WriteData;

  procedure WriteGclData(AXmjNode: TXmjNode);
  var
    iGcl: Integer;
    GclNode: TGclNode;
  begin
    for iGcl := 0 to AXmjNode.GclList.Count - 1 do
    begin
      GclNode := TGclNode(AXmjNode.GclList.Items[iGcl]);
      cdsBGLExecution.Append;
      cdsBGLExecutionB_Code.AsString := GclNode.B_Code;
      cdsBGLExecutionName.AsString := GclNode.Name;
      cdsBGLExecutionUnits.AsString := GclNode.Units;
      cdsBGLExecutionPrice.AsFloat := GclNode.Price;
      cdsBGLExecutionQuantity.AsFloat := GclNode.Quantity;
      cdsBGLExecutionTotalPrice.AsFloat := GclNode.TotalPrice;
      cdsBGLExecution.Post;
    end;
  end;

  procedure WriteXmjData(ABGLNode: TBGLNode);
  var
    iXmj: Integer;
    XmjNode: TXmjNode;
  begin
    for iXmj := 0 to ABGLNode.XmjList.Count - 1 do
    begin
      XmjNode := TXmjNode(ABGLNode.XmjList.Items[iXmj]);
      cdsBGLExecution.Append;
      cdsBGLExecutionCode.AsString := XmjNode.Code;
      cdsBGLExecutionName.AsString := XmjNode.Name;
      cdsBGLExecutionUnits.AsString := XmjNode.Units;
      cdsBGLExecution.Post;
      WriteGclData(XmjNode);
    end;
  end;

var
  iBGL: Integer;
  BGLNode: TBGLNode;
begin
  for iBGL := 0 to FBGLList.Count - 1 do
  begin
    BGLNode := TBGLNode(FBGLList.Items[iBGL]);
    cdsBGLExecution.Append;
    cdsBGLExecutionBGLCode.AsString := BGLNode.BGLCode;
    cdsBGLExecution.Post;
    WriteXmjData(BGLNode);
  end;
end;

{ TXmjNode }

function TXmjNode.AddGclNode(AB_Code: string): TGclNode;
var
  Node: TGclNode;
  i, iIndex: Integer;
  sB_Code1, sB_Code2: string;
begin
  // 新增
  Result := TGclNode.Create;
  Result.B_Code := AB_Code;
  // List中根据顺序新增
  iIndex := FGclList.Count;
  sB_Code1 := B_CodeToIndexCode(AB_Code);
  for i := 0 to FGclList.Count - 1 do
  begin
    Node := TGclNode(FGclList.Items[i]);
    sB_Code2 := B_CodeToIndexCode(Node.B_Code);
    if sB_Code1 < sB_Code2 then
    begin
      iIndex := i;
      Break;
    end;
  end;
  FGclList.Insert(iIndex, Result);
end;

constructor TXmjNode.Create;
begin
  FGclList := TList.Create;
end;

destructor TXmjNode.Destroy;
begin
  ClearObjects(FGclList);
  FGclList.Free;
  inherited;
end;

{ TBGLNode }

function TBGLNode.AddXmjNode(ACode: string): TXmjNode;
var
  Node: TXmjNode;
  i, iIndex: Integer;
  sCode1, sCode2: string;
begin
  // 新增
  Result := TXmjNode.Create;
  Result.Code := ACode;
  // List中根据顺序新增
  iIndex := FXmjList.Count;
  sCode1 := ConvertDigitCode(ACode, 3);
  for i := 0 to FXmjList.Count - 1 do
  begin
    Node := TXmjNode(FXmjList.Items[i]);
    sCode2 := ConvertDigitCode(Node.Code, 3);
    if sCode1 < sCode2 then
    begin
      iIndex := i;
      Break;
    end;
  end;
  FXmjList.Insert(iIndex, Result);
end;

constructor TBGLNode.Create;
begin
  FXmjList := TList.Create;
end;

destructor TBGLNode.Destroy;
begin
  ClearObjects(FXmjList);
  FXmjList.Free;
  inherited;
end;

function TBGLNode.FindXmjNode(ACode: string): TXmjNode;
var
  iXmj: Integer;
  XmjNode: TXmjNode;
begin
  Result := nil;
  for iXmj := 0 to FXmjList.Count - 1 do
  begin
    XmjNode := TXmjNode(FXmjList.Items[iXmj]);
    if SameText(XmjNode.Code, ACode) then
    begin
      Result := XmjNode;
      Break;
    end;
  end;
end;

end.
