unit GclBillsGatherModel;
// 单项目的工程量清单汇总

interface

uses
  Classes, mDataRecord, BillsTree, CalcDecimal;

type
  TGatherDataWriteEvent = procedure (AGcls, AXmjs: TList) of object;

  TLeafXmjNode = class
  private
    FID: Integer;
    FXmjCode: string;
    FXmjName: string;
    FXmjUnits: string;
    FPeg: string;
    FNameDanWei: string;
    FNameFenBu: string;
    FNameFenXiang: string;
    FNameUnit: string;
    FPosition: string;
    FDrawingCode: string;
  public
    constructor Create(ALeafXmj, APeg: TBillsIDTreeNode);

    property ID: Integer read FID;
    property XmjCode: string read FXmjCode;
    property XmjName: string read FXmjName;
    property XmjUnits: string read FXmjUnits;
    property Peg: string read FPeg;
    property NameDanWei: string read FNameDanWei;
    property NameFenBu: string read FNameFenBu;
    property NameFenXiang: string read FNameFenXiang;
    property NameUnit: string read FNameUnit;
    property Position: string read FPosition;
    property DrawingCode: string read FDrawingCode;
  end;

  TDetailGclNode = class
  private
    FID: Integer;
    FBillsID: Integer;
    FTreeSerialNo: Integer;

    FOrgQuantity: Double;
    FOrgTotalPrice: Double;
    FMisQuantity: Double;
    FMisTotalPrice: Double;
    FOthQuantity: Double;
    FOthTotalPrice: Double;

    FQuantity: Double;
    FTotalPrice: Double;

    FCurDealQuantity: Double;
    FCurDealTotalPrice: Double;
    FCurQcQuantity: Double;
    FCurQcTotalPrice: Double;
    FCurGatherQuantity: Double;
    FCurGatherTotalPrice: Double;

    FPreDealQuantity: Double;
    FPreDealTotalPrice: Double;
    FPreQcQuantity: Double;
    FPreQcTotalPrice: Double;
    FPreGatherQuantity: Double;
    FPreGatherTotalPrice: Double;

    FEndDealQuantity: Double;
    FEndDealTotalPrice: Double;
    FEndQcQuantity: Double;
    FEndQcTotalPrice: Double;
    FEndGatherQuantity: Double;
    FEndGatherTotalPrice: Double;

    FAddDealQuantity: Double;
    FAddDealTotalPrice: Double;
    FAddQcQuantity: Double;
    FAddQcTotalPrice: Double;
    FAddGatherQuantity: Double;
    FAddGatherTotalPrice: Double;

    FPM_PreTotalPrice: Double;
    FPM_TotalPrice: Double;

    FLeafXmj: TLeafXmjNode;
    function GetPercent: Double;
  public
    constructor Create(AID: Integer);

    property ID: Integer read FID;
    property BillsID: Integer read FBillsID write FBillsID;
    property TreeSerialNo: Integer read FTreeSerialNo write FTreeSerialNo;

    property OrgQuantity: Double read FOrgQuantity write FOrgQuantity;
    property OrgTotalPrice: Double read FOrgTotalPrice write FOrgTotalPrice;
    property MisQuantity: Double read FMisQuantity write FMisQuantity;
    property MisTotalPrice: Double read FMisTotalPrice write FMisTotalPrice;
    property OthQuantity: Double read FOthQuantity write FOthQuantity;
    property OthTotalPrice: Double read FOthTotalPrice write FOthTotalPrice;

    property Quantity: Double read FQuantity write FQuantity;
    property TotalPrice: Double read FTotalPrice write FTotalPrice;

    property CurDealQuantity: Double read FCurDealQuantity write FCurDealQuantity;
    property CurDealTotalPrice: Double read FCurDealTotalPrice write FCurDealTotalPrice;
    property CurQcQuantity: Double read FCurQcQuantity write FCurQcQuantity;
    property CurQcTotalPrice: Double read FCurQcTotalPrice write FCurQcTotalPrice;
    property CurGatherQuantity: Double read FCurGatherQuantity write FCurGatherQuantity;
    property CurGatherTotalPrice: Double read FCurGatherTotalPrice write FCurGatherTotalPrice;

    property PreDealQuantity: Double read FPreDealQuantity write FPreDealQuantity;
    property PreDealTotalPrice: Double read FPreGatherTotalPrice write FPreGatherTotalPrice;
    property PreQcQuantity: Double read FPreQcQuantity write FPreQcQuantity;
    property PreQcTotalPrice: Double read FPreQcTotalPrice write FPreQcTotalPrice;
    property PreGatherQuantity: Double read FPreGatherQuantity write FPreGatherQuantity;
    property PreGatherTotalPrice: Double read FPreGatherTotalPrice write FPreGatherTotalPrice;

    property EndDealQuantity: Double read FEndDealQuantity write FEndDealQuantity;
    property EndDealTotalPrice: Double read FEndDealTotalPrice write FEndDealTotalPrice;
    property EndQcQuantity: Double read FEndQcQuantity write FEndQcQuantity;
    property EndQcTotalPrice: Double read FEndQcTotalPrice write FEndQcTotalPrice;
    property EndGatherQuantity: Double read FEndGatherQuantity write FEndGatherQuantity;
    property EndGatherTotalPrice: Double read FEndGatherTotalPrice write FEndGatherTotalPrice;

    property Percent: Double read GetPercent;

    property AddDealQuantity: Double read FAddDealQuantity write FAddDealQuantity;
    property AddDealTotalPrice: Double read FAddDealTotalPrice write FAddDealTotalPrice;
    property AddQcQuantity: Double read FAddQcQuantity write FAddQcQuantity;
    property AddQcTotalPrice: Double read FAddQcTotalPrice write FAddQcQuantity;
    property AddGatherQuantity: Double read FAddGatherQuantity write FAddGatherQuantity;
    property AddGatherTotalPrice: Double read FAddGatherTotalPrice write FAddGatherTotalPrice;

    property PM_PreTotalPrice: Double read FPM_PreTotalPrice write FPM_PreTotalPrice;
    property PM_TotalPrice: Double read FPM_TotalPrice write FPM_TotalPrice;

    property LeafXmj: TLeafXmjNode read FLeafXmj write FLeafXmj;
  end;

  TDetailDealNode = class
  private
    FID: Integer;
    FDealID: Integer;

    FQuantity: Double;
    FTotalPrice: Double;
  public
    constructor Create(AID: Integer);

    property ID: Integer read FID;
    property DealID: Integer read FDealID write FDealID;

    property Quantity: Double read FQuantity write FQuantity;
    property TotalPrice: Double read FTotalPrice write FTotalPrice;
  end;

  TDetailBGLNode = class
  private
    FID: Integer;
    FBGBillsID: Integer;
    FBGLID: Integer;

    FBGLCode: string;
    FBGLName: string;
    FBGLApprovalCode: string;
    FBGLDrawingCode: string;

    FQuantity: Double;
    FTotalPrice: Double;
  public
    constructor Create(AID: Integer);

    property ID: Integer read FID;
    property BGBillsID: Integer read FBGBillsID write FBGBillsID;
    property BGLID: Integer read FBGLID write FBGLID;

    property BGLCode: string read FBGLCode write FBGLCode;
    property BGLName: string read FBGLName write FBGLName;
    property BGLApprovalCode: string read FBGLApprovalCode write FBGLApprovalCode;
    property BGLDrawingCode: string read FBGLDrawingCode write FBGLDrawingCode;

    property Quantity: Double read FQuantity write FQuantity;
    property TotalPrice: Double read FTotalPrice write FTotalPrice;
  end;

  TGclNode = class
  private
    FDetailGcls: TList;
    FDetailDeals: TList;
    FDetailBGLs: TList;
    FLeafXmjs: TList;

    FID: Integer;

    FB_Code: string;
    FIndexCode: string;
    FName: string;
    FUnits: string;
    FPrice: Double;

    FOrgQuantity: Double;
    FOrgTotalPrice: Double;
    FMisQuantity: Double;
    FMisTotalPrice: Double;
    FOthQuantity: Double;
    FOthTotalPrice: Double;

    FQuantity: Double;
    FTotalPrice: Double;

    FCurDealQuantity: Double;
    FCurDealTotalPrice: Double;
    FCurQcQuantity: Double;
    FCurQcTotalPrice: Double;
    FCurGatherQuantity: Double;
    FCurGatherTotalPrice: Double;

    FPreDealQuantity: Double;
    FPreDealTotalPrice: Double;
    FPreQcQuantity: Double;
    FPreQcTotalPrice: Double;
    FPreGatherQuantity: Double;
    FPreGatherTotalPrice: Double;

    FEndDealQuantity: Double;
    FEndDealTotalPrice: Double;
    FEndQcQuantity: Double;
    FEndQcTotalPrice: Double;
    FEndGatherQuantity: Double;
    FEndGatherTotalPrice: Double;

    FAddDealQuantity: Double;
    FAddDealTotalPrice: Double;
    FAddQcQuantity: Double;
    FAddQcTotalPrice: Double;
    FAddGatherQuantity: Double;
    FAddGatherTotalPrice: Double;

    FDealQuantity: Double;
    FDealTotalPrice: Double;

    FBGLQuantity: Double;
    FBGLTotalPrice: Double;

    FDeal_BGLQuantity: Double;
    FDeal_BGLTotalPrice: Double;
    FDeal_BGLPercent: Double;
    FDecimal: TCalcDecimal;

    procedure InitCalculate;
    procedure GatherDetailGcl;
    procedure GatherDetailDeal;
    procedure GatherDetailBGL;
    procedure CalculateOther;

    procedure SetB_Code(const Value: string);
    function GetDetailBGL(AIndex: Integer): TDetailBGLNode;
    function GetDetailBGLCount: Integer;
    function GetDetailDeal(AIndex: Integer): TDetailDealNode;
    function GetDetailDealCount: Integer;
    function GetDetailGcl(AIndex: Integer): TDetailGclNode;
    function GetDetailGclCount: Integer;
    function GetLeafXmjCount: Integer;
    function GetLeafXmj(AIndex: Integer): TLeafXmjNode;
  public
    constructor Create(AID: Integer; ADecimal: TCalcDecimal);
    destructor Destroy; override;

    procedure AddLeafXmj(ALeafXmj: TLeafXmjNode);
    function AddDetailGcl(AID: Integer): TDetailGclNode;
    function AddDetailDeal(AID: Integer): TDetailDealNode;
    function AddDetailBGL(AID: Integer): TDetailBGLNode;

    procedure Calculate;

    property ID: Integer read FID;

    property B_Code: string read FB_Code write SetB_Code;
    property IndexCode: string read FIndexCode;
    property Name: string read FName write FName;
    property Units: string read FUnits write FUnits;
    property Price: Double read FPrice write FPrice;

    property OrgQuantity: Double read FOrgQuantity;
    property OrgTotalPrice: Double read FOrgTotalPrice;
    property MisQuantity: Double read FMisQuantity;
    property MisTotalPrice: Double read FMisTotalPrice;
    property OthQuantity: Double read FOthQuantity;
    property OthTotalPrice: Double read FOthTotalPrice;

    property Quantity: Double read FQuantity;
    property TotalPrice: Double read FTotalPrice;

    property CurDealQuantity: Double read FCurDealQuantity;
    property CurDealTotalPrice: Double read FCurDealTotalPrice;
    property CurQcQuantity: Double read FCurQcQuantity;
    property CurQcTotalPrice: Double read FCurQcTotalPrice;
    property CurGatherQuantity: Double read FCurGatherQuantity;
    property CurGatherTotalPrice: Double read FCurGatherTotalPrice;

    property PreDealQuantity: Double read FPreDealQuantity;
    property PreDealTotalPrice: Double read FPreGatherTotalPrice;
    property PreQcQuantity: Double read FPreQcQuantity;
    property PreQcTotalPrice: Double read FPreQcTotalPrice;
    property PreGatherQuantity: Double read FPreGatherQuantity;
    property PreGatherTotalPrice: Double read FPreGatherTotalPrice;

    property EndDealQuantity: Double read FEndDealQuantity;
    property EndDealTotalPrice: Double read FEndDealTotalPrice;
    property EndQcQuantity: Double read FEndQcQuantity;
    property EndQcTotalPrice: Double read FEndQcTotalPrice;
    property EndGatherQuantity: Double read FEndGatherQuantity;
    property EndGatherTotalPrice: Double read FEndGatherTotalPrice;

    property AddDealQuantity: Double read FAddDealQuantity;
    property AddDealTotalPrice: Double read FAddGatherTotalPrice;
    property AddQcQuantity: Double read FAddQcQuantity;
    property AddQcTotalPrice: Double read FAddQcTotalPrice;
    property AddGatherQuantity: Double read FAddGatherQuantity;
    property AddGatherTotalPrice: Double read FAddGatherTotalPrice;

    property DealQuantity: Double read FDealQuantity;
    property DealTotalPrice: Double read FDealTotalPrice;

    property BGLQuantity: Double read FBGLQuantity;
    property BGLTotalPrice: Double read FBGLTotalPrice;

    // ---------- Calculate --------------
    property Deal_BGLQuantity: Double read FDeal_BGLQuantity;
    property Deal_BGLTotalPrice: Double read FDeal_BGLTotalPrice;
    property Deal_BGLPercent: Double read FDeal_BGLPercent;
    // -----------------------------------

    property DetailGclCount: Integer read GetDetailGclCount;
    property DetailGcl[AIndex: Integer]: TDetailGclNode read GetDetailGcl;
    property LeafXmjCount: Integer read GetLeafXmjCount;
    property LeafXmj[AIndex: Integer]: TLeafXmjNode read GetLeafXmj;

    property DetailDealCount: Integer read GetDetailDealCount;
    property DetailDeal[AIndex: Integer]: TDetailDealNode read GetDetailDeal;

    property DetailBGLCount: Integer read GetDetailBGLCount;
    property DetailBGL[AIndex: Integer]: TDetailBGLNode read GetDetailBGL;

    property Decimal: TCalcDecimal read FDecimal;
  end;

  TGclGatherModel = class
  private
    FProjectData: TObject;
    FBillsTree: TBillsIDTree;
    FMergeDetailGcl: Boolean;
    FGatherDeal: Boolean;
    FGatherBGL: Boolean;

    FGcls: TList;
    FXmjs: TList;
    FNewGclID: Integer;
    FNewDetailGclID: Integer;
    FNewDetailDealID: Integer;
    FNewDetailBGLID: Integer;

    FWriteGatherData: TGatherDataWriteEvent;
    FDecimal: TCalcDecimal;

    procedure BeginGather;
    procedure EndGather;

    function FindLeafXmj(ALeafXmj: TBillsIDTreeNode): TLeafXmjNode;
    function NewLeafXmj(ALeafXmj: TBillsIDTreeNode): TLeafXmjNode;
    function GetLeafXmj(ANode: TBillsIDTreeNode): TLeafXmjNode;

    function FindGclNode(const AB_Code, AName, AUnits: string; APrice: Double): TGclNode;
    function NewGclNode(const AB_Code, AName, AUnits: string; APrice: Double): TGclNode;
    function GetGclNode(const AB_Code, AName, AUnits: string; APrice: Double): TGclNode; overload;
    function GetGclNode(ARec: TBillsRecord): TGclNode; overload;

    procedure AddBillsNode(ANode: TMeasureBillsIDTreeNode);
    procedure GatherBillsData;
    procedure GatherDealData;
    procedure GatherBGLData;

    procedure CalculateAll;

    function GetNewDetailBGLID: Integer;
    function GetNewDetailDealID: Integer;
    function GetNewDetailGclID: Integer;
  public
    constructor Create(AProjectData: TObject);
    destructor Destroy; override;

    procedure Execute;

    property GatherDeal: Boolean read FGatherDeal write FGatherDeal;
    property GatherBGL: Boolean read FGatherBGL write FGatherBGL;

    property NewDetailGclID: Integer read GetNewDetailGclID;
    property NewDetailDealID: Integer read GetNewDetailDealID;
    property NewDetailBGLID: Integer read GetNewDetailBGLID;

    // 在使用汇总模型的数据单元创建数据库写入方法，并赋值，否则汇总数据不写入
    property WriteGatherData: TGatherDataWriteEvent read FWriteGatherData write FWriteGatherData;

    property Decimal: TCalcDecimal read FDecimal;
  end;

implementation

uses
  ZhAPI, SysUtils, ProjectData, UtilMethods, sdDB, sdIDTree, BGLDm, DB,
  Math;

{ TGclGatherModel }

procedure TGclGatherModel.AddBillsNode(ANode: TMeasureBillsIDTreeNode);
var
  vGclNode: TGclNode;
  vDetailGclNode: TDetailGclNode;
  vLeafXmj: TLeafXmjNode;
begin
  vGclNode := GetGclNode(ANode.Rec);
  vDetailGclNode := vGclNode.AddDetailGcl(NewDetailGclID);
  vDetailGclNode.BillsID := ANode.ID;
  vDetailGclNode.TreeSerialNo := ANode.MajorIndex;

  vDetailGclNode.OrgQuantity := ANode.Rec.OrgQuantity.AsFloat;
  vDetailGclNode.OrgTotalPrice := ANode.Rec.OrgTotalPrice.AsFloat;
  vDetailGclNode.MisQuantity := ANode.Rec.MisQuantity.AsFloat;
  vDetailGclNode.MisTotalPrice := ANode.Rec.MisTotalPrice.AsFloat;
  vDetailGclNode.OthQuantity := ANode.Rec.OthQuantity.AsFloat;
  vDetailGclNode.OthTotalPrice := ANode.Rec.OthTotalPrice.AsFloat;

  vDetailGclNode.Quantity := ANode.Rec.Quantity.AsFloat;
  vDetailGclNode.TotalPrice := ANode.Rec.TotalPrice.AsFloat;

  if Assigned(ANode.StageRec) then
  begin
    vDetailGclNode.CurDealQuantity := ANode.StageRec.DealQuantity.AsFloat;
    vDetailGclNode.CurDealTotalPrice := ANode.StageRec.DealTotalPrice.AsFloat;
    vDetailGclNode.CurQcQuantity := ANode.StageRec.QcQuantity.AsFloat;
    vDetailGclNode.CurQcTotalPrice := ANode.StageRec.QcTotalPrice.AsFloat;
    vDetailGclNode.CurGatherQuantity := ANode.StageRec.GatherQuantity.AsFloat;
    vDetailGclNode.CurGatherTotalPrice := ANode.StageRec.GatherTotalPrice.AsFloat;

    vDetailGclNode.PreDealQuantity := ANode.StageRec.PreDealQuantity.AsFloat;
    vDetailGclNode.PreDealTotalPrice := ANode.StageRec.PreDealTotalPrice.AsFloat;
    vDetailGclNode.PreQcQuantity := ANode.StageRec.PreQcQuantity.AsFloat;
    vDetailGclNode.PreQcTotalPrice := ANode.StageRec.PreQcTotalPrice.AsFloat;
    vDetailGclNode.PreGatherQuantity := ANode.StageRec.PreGatherQuantity.AsFloat;
    vDetailGclNode.PreGatherTotalPrice := ANode.StageRec.PreGatherTotalPrice.AsFloat;

    vDetailGclNode.EndDealQuantity := ANode.StageRec.EndDealQuantity.AsFloat;
    vDetailGclNode.EndDealTotalPrice := ANode.StageRec.EndDealTotalPrice.AsFloat;
    vDetailGclNode.EndQcQuantity := ANode.StageRec.EndQcQuantity.AsFloat;
    vDetailGclNode.EndQcTotalPrice := ANode.StageRec.EndQcTotalPrice.AsFloat;
    vDetailGclNode.EndGatherQuantity := ANode.StageRec.EndGatherQuantity.AsFloat;
    vDetailGclNode.EndGatherTotalPrice := ANode.StageRec.EndGatherTotalPrice.AsFloat;

    vDetailGclNode.PM_PreTotalPrice := ANode.StageRec.PM_PreTotalPrice.AsFloat;
    vDetailGclNode.PM_TotalPrice := ANode.StageRec.PM_TotalPrice.AsFloat;
  end;

  vDetailGclNode.AddDealQuantity := ANode.Rec.AddDealQuantity.AsFloat;
  vDetailGclNode.AddDealTotalPrice := ANode.Rec.AddDealTotalPrice.AsFloat;
  vDetailGclNode.AddQcQuantity := ANode.Rec.AddQcQuantity.AsFloat;
  vDetailGclNode.AddQcTotalPrice := ANode.Rec.AddQcTotalPrice.AsFloat;
  vDetailGclNode.AddGatherQuantity := ANode.Rec.AddGatherQuantity.AsFloat;
  vDetailGclNode.AddGatherTotalPrice := ANode.Rec.AddGatherTotalPrice.AsFloat;

  vDetailGclNode.LeafXmj := GetLeafXmj(ANode);
  vGclNode.AddLeafXmj(vDetailGclNode.LeafXmj);
end;

procedure TGclGatherModel.BeginGather;
begin
  FGcls := TList.Create;
  FXmjs := TList.Create;
end;

procedure TGclGatherModel.CalculateAll;
var
  iGcl: Integer;
begin
  for iGcl := 0 to FGcls.Count - 1 do
    TGclNode(FGcls.Items[iGcl]).Calculate;
end;

constructor TGclGatherModel.Create(AProjectData: TObject);
begin
  FProjectData := AProjectData;
  FBillsTree := TProjectData(FProjectData).BillsMeasureData.BillsMeasureTree;
  FGatherDeal := False;
  FGatherBGL := False;
  FDecimal := TProjectData(FProjectData).ProjProperties.DecimalManager.Common;
end;

destructor TGclGatherModel.Destroy;
begin
  inherited;
end;

procedure TGclGatherModel.EndGather;
begin
  ClearObjects(FXmjs);
  FXmjs.Free;
  ClearObjects(FGcls);
  FGcls.Free;
end;

procedure TGclGatherModel.Execute;
begin
  BeginGather;
  try
    GatherBillsData;
    GatherDealData;
    GatherBGLData;
    CalculateAll;
    if Assigned(FWriteGatherData) then
      FWriteGatherData(FGcls, FXmjs);
  finally
    EndGather;
  end;
end;

function TGclGatherModel.FindGclNode(const AB_Code, AName, AUnits: string;
  APrice: Double): TGclNode;
var
  i: Integer;
  vGcl: TGclNode;
begin
  Result := nil;
  for i := 0 to FGcls.Count - 1 do
  begin
    vGcl := TGclNode(FGcls.Items[i]);
    if SameText(vGcl.B_Code, TrimRight(AB_Code)) and
       SameText(vGcl.Name, TrimRight(AName)) and
       SameText(vGcl.Units, TrimRight(AUnits)) and
       (abs(vGcl.Price - APrice) < 0.001) then
    begin
      Result := vGcl;
      Break;
    end;
  end;
end;

function TGclGatherModel.FindLeafXmj(
  ALeafXmj: TBillsIDTreeNode): TLeafXmjNode;
var
  iXmj: Integer;
  vLeafXmj: TLeafXmjNode;
begin
  Result := nil;
  for iXmj := 0 to FXmjs.Count - 1 do
  begin
    vLeafXmj := TLeafXmjNode(FXmjs.Items[iXmj]);
    if vLeafXmj.ID = ALeafXmj.ID then
    begin
      Result := vLeafXmj;
      Break;
    end;
  end;
end;

procedure TGclGatherModel.GatherBGLData;
var
  vGclNode: TGclNode;
  DetailBGL: TDetailBGLNode;
begin
  if not FGatherBGL then Exit;

  with TProjectData(FProjectData).BGLData do
  begin
    cdsBGBills.First;
    while not cdsBGBills.Eof do
    begin
      vGclNode := GetGclNode(cdsBGBillsB_Code.AsString, cdsBGBillsName.AsString,
          cdsBGBillsUnits.AsString, cdsBGBillsPrice.AsFloat);

      if cdsBGL.FindKey([cdsBGBillsBGID.AsInteger]) then
      begin
        DetailBGL := vGclNode.AddDetailBGL(NewDetailBGLID);
        DetailBGL.BGBillsID := cdsBGBillsID.AsInteger;
        DetailBGL.BGLCode := cdsBGLCode.AsString;
        DetailBGL.BGLName := cdsBGLName.AsString;
        DetailBGL.BGLApprovalCode := cdsBGLApprovalCode.AsString;
        DetailBGL.BGLDrawingCode := cdsBGLDrawingCode.AsString;
        DetailBGL.BGLID := cdsBGBillsBGID.AsInteger;
        DetailBGL.Quantity := cdsBGBillsQuantity.AsFloat;
        DetailBGL.TotalPrice := cdsBGBillsTotalPrice.AsFloat;
      end;
      cdsBGBills.Next;
    end;
  end;
end;

procedure TGclGatherModel.GatherBillsData;
var
  i: Integer;
  vNode: TMeasureBillsIDTreeNode;
begin
  for i := 0 to FBillsTree.Count - 1 do
  begin
    vNode := TMeasureBillsIDTreeNode(FBillsTree.Items[i]);
    if not vNode.HasChildren and (vNode.Rec.B_Code.AsString <> '') then
      AddBillsNode(vNode);
  end;
end;

procedure TGclGatherModel.GatherDealData;
var
  vGclNode: TGclNode;
  vDetailDeal: TDetailDealNode;
  iDeal: Integer;
  Rec: TsdDataRecord;
begin
  if not FGatherDeal then Exit;

  with TProjectData(FProjectData).DealBillsData do
    for iDeal := 0 to sddDealBills.RecordCount - 1 do
    begin
      Rec := sddDealBills.Records[iDeal];
      vGclNode := GetGclNode(Rec.ValueByName('B_Code').AsString, Rec.ValueByName('Name').AsString,
          Rec.ValueByName('Units').AsString, Rec.ValueByName('Price').AsFloat);
      vDetailDeal := vGclNode.AddDetailDeal(NewDetailDealID);

      vDetailDeal.Quantity := Rec.ValueByName('Quantity').AsFloat;
      vDetailDeal.TotalPrice := Rec.ValueByName('TotalPrice').AsFloat;
    end;
end;

function TGclGatherModel.GetGclNode(ARec: TBillsRecord): TGclNode;
begin
  Result := GetGclNode(ARec.B_Code.AsString, ARec.Name.AsString,
      ARec.Units.AsString, ARec.Price.AsFloat);
end;

function TGclGatherModel.GetGclNode(const AB_Code, AName, AUnits: string;
  APrice: Double): TGclNode;
begin
  Result := FindGclNode(AB_Code, AName, AUnits, APrice);
  if not Assigned(Result) then
    Result := NewGclNode(AB_Code, AName, AUnits, APrice);
end;

function TGclGatherModel.GetLeafXmj(
  ANode: TBillsIDTreeNode): TLeafXmjNode;

  function GetFirstXmjParent: TBillsIDTreeNode;
  begin
    Result := ANode;
    while Assigned(Result) and (Result.Rec.B_Code.AsString <> '') do
      Result := TBillsIDTreeNode(Result.Parent);  
  end;

var
  vFirstXmjParent: TBillsIDTreeNode;
begin
  vFirstXmjParent := GetFirstXmjParent;
  Result := nil;
  if not Assigned(vFirstXmjParent) then Exit;

  Result := FindLeafXmj(vFirstXmjParent);
  if not Assigned(Result) then
    Result := NewLeafXmj(vFirstXmjParent);
end;

function TGclGatherModel.GetNewDetailBGLID: Integer;
begin
  Result := FNewDetailBGLID;
  Inc(FNewDetailBGLID)
end;

function TGclGatherModel.GetNewDetailDealID: Integer;
begin
  Result := FNewDetailDealID;
  Inc(FNewDetailDealID);
end;

function TGclGatherModel.GetNewDetailGclID: Integer;
begin
  Result := FNewDetailGclID;
  Inc(FNewDetailGclID);
end;

function TGclGatherModel.NewGclNode(const AB_Code, AName, AUnits: string;
  APrice: Double): TGclNode;
begin
  Result := TGclNode.Create(FNewGclID, FDecimal);
  FGcls.Add(Result);
  Result.B_Code := TrimRight(AB_Code);
  Result.Name := TrimRight(AName);
  Result.Units := TrimRight(AUnits);
  Result.Price := APrice;
  Inc(FNewGclID);
end;

function TGclGatherModel.NewLeafXmj(
  ALeafXmj: TBillsIDTreeNode): TLeafXmjNode;

  function GetPegNode(ANode: TBillsIDTreeNode): TBillsIDTreeNode;
  begin
    Result := nil;
    if not Assigned(ANode) then Exit;
    if CheckPeg(ANode.Rec.Name.AsString) then
      Result := ANode
    else
      Result := GetPegNode(TBillsIDTreeNode(ANode.Parent));
  end;

var
  vPeg: TBillsIDTreeNode;
begin
  vPeg := GetPegNode(ALeafXmj);
  Result := TLeafXmjNode.Create(ALeafXmj, vPeg);
  FXmjs.Add(Result);
end;

{ TGclNode }

function TGclNode.AddDetailBGL(AID: Integer): TDetailBGLNode;
begin
  Result := TDetailBGLNode.Create(AID);
  FDetailBGLs.Add(Result);
end;

function TGclNode.AddDetailDeal(AID: Integer): TDetailDealNode;
begin
  Result := TDetailDealNode.Create(AID);
  FDetailDeals.Add(Result);
end;

function TGclNode.AddDetailGcl(AID: Integer): TDetailGclNode;
begin
  Result := TDetailGclNode.Create(AID);
  FDetailGcls.Add(Result);
end;

procedure TGclNode.AddLeafXmj(ALeafXmj: TLeafXmjNode);
begin
  if FLeafXmjs.IndexOf(ALeafXmj) = -1 then
    FLeafXmjs.Add(ALeafXmj); 
end;

procedure TGclNode.Calculate;
begin
  InitCalculate;
  GatherDetailGcl;
  GatherDetailDeal;
  GatherDetailBGL;
  CalculateOther;
end;

procedure TGclNode.CalculateOther;
begin
  FDeal_BGLQuantity := Decimal.Quantity.RoundTo(FQuantity + FBGLQuantity);
  FDeal_BGLTotalPrice := Decimal.TotalPrice.RoundTo(FTotalPrice + FBGLTotalPrice);
  if FDeal_BGLTotalPrice <> 0 then
    FDeal_BGLPercent := CommonRoundTo(FEndGatherTotalPrice/FDeal_BGLTotalPrice*100, -2)
  else
    FDeal_BGLPercent := 0;
end;

constructor TGclNode.Create(AID: Integer; ADecimal: TCalcDecimal);
begin
  FID := AID;
  FDetailGcls := TList.Create;
  FDetailDeals := TList.Create;
  FDetailBGLs := TList.Create;
  FLeafXmjs := TList.Create;
  FDecimal := ADecimal;
end;

destructor TGclNode.Destroy;
begin
  FLeafXmjs.Free;
  ClearObjects(FDetailBGLs);
  FDetailBGLs.Free;
  ClearObjects(FDetailDeals);
  FDetailDeals.Free;
  ClearObjects(FDetailGcls);
  FDetailGcls.Free;
  inherited;
end;

procedure TGclNode.GatherDetailBGL;
var
  iBGL: Integer;
  vDetailBGL: TDetailBGLNode;
begin
  for iBGL := 0 to DetailBGLCount - 1 do
  begin
    vDetailBGL := DetailBGL[iBGL];
    FBGLQuantity := FBGLQuantity + vDetailBGL.Quantity;
    FBGLTotalPrice := FBGLTotalPrice + vDetailBGL.TotalPrice;
  end;
end;

procedure TGclNode.GatherDetailDeal;
var
  iDeal: Integer;
  vDetailDeal: TDetailDealNode;
begin
  for iDeal := 0 to DetailDealCount - 1 do
  begin
    vDetailDeal := DetailDeal[iDeal];
    FDealQuantity := FDealQuantity + vDetailDeal.Quantity;
    FDealTotalPrice := FDealTotalPrice + vDetailDeal.TotalPrice;
  end;
end;

procedure TGclNode.GatherDetailGcl;
var
  iGcl: Integer;
  vDetailGcl: TDetailGclNode;
begin
  for iGcl := 0 to DetailGclCount - 1 do
  begin
    vDetailGcl := DetailGcl[iGcl];
    FOrgQuantity := FOrgQuantity + vDetailGcl.OrgQuantity;
    FOrgTotalPrice := FOrgTotalPrice + vDetailGcl.OrgTotalPrice;
    FMisQuantity := FMisQuantity + vDetailGcl.MisQuantity;
    FMisTotalPrice := FMisTotalPrice + vDetailGcl.MisTotalPrice;
    FOthQuantity := FOthQuantity + vDetailGcl.OthQuantity;
    FOthTotalPrice := FOthTotalPrice + vDetailGcl.OthTotalPrice;

    FQuantity := FQuantity + vDetailGcl.Quantity;
    FTotalPrice := FTotalPrice + vDetailGcl.TotalPrice;

    FCurDealQuantity := FCurDealQuantity + vDetailGcl.CurDealQuantity;
    FCurDealTotalPrice := FCurDealTotalPrice + vDetailGcl.CurDealTotalPrice;
    FCurQcQuantity := FCurQcQuantity + vDetailGcl.CurQcQuantity;
    FCurQcTotalPrice := FCurQcTotalPrice + vDetailGcl.CurQcTotalPrice;
    FCurGatherQuantity := FCurGatherQuantity + vDetailGcl.CurGatherQuantity;
    FCurGatherTotalPrice := FCurGatherTotalPrice + vDetailGcl.CurGatherTotalPrice;

    FPreDealQuantity := FPreDealQuantity + vDetailGcl.PreDealQuantity;
    FPreDealTotalPrice := FPreDealTotalPrice + vDetailGcl.PreDealTotalPrice;
    FPreQcQuantity := FPreQcQuantity + vDetailGcl.PreQcQuantity;
    FPreQcTotalPrice := FPreQcTotalPrice + vDetailGcl.PreQcTotalPrice;
    FPreGatherQuantity := FPreGatherQuantity + vDetailGcl.PreGatherQuantity;
    FPreGatherTotalPrice := FPreGatherTotalPrice + vDetailGcl.PreGatherTotalPrice;

    FEndDealQuantity := FEndDealQuantity + vDetailGcl.EndDealQuantity;
    FEndDealTotalPrice := FEndDealTotalPrice + vDetailGcl.EndDealTotalPrice;
    FEndQcQuantity := FEndQcQuantity + vDetailGcl.EndQcQuantity;
    FEndQcTotalPrice := FEndQcTotalPrice + vDetailGcl.EndQcTotalPrice;
    FEndGatherQuantity := FEndGatherQuantity + vDetailGcl.EndGatherQuantity;
    FEndGatherTotalPrice := FEndGatherTotalPrice + vDetailGcl.EndGatherTotalPrice;

    FAddDealQuantity := FAddDealQuantity + vDetailGcl.AddDealQuantity;
    FAddDealTotalPrice := FAddDealTotalPrice + vDetailGcl.AddDealTotalPrice;
    FAddQcQuantity := FAddQcQuantity + vDetailGcl.AddQcQuantity;
    FAddQcTotalPrice := FAddQcTotalPrice + vDetailGcl.AddQcTotalPrice;
    FAddGatherQuantity := FAddGatherQuantity + vDetailGcl.AddGatherQuantity;
    FAddGatherTotalPrice := FAddGatherTotalPrice + vDetailGcl.AddGatherTotalPrice;
  end;
end;

function TGclNode.GetDetailBGL(AIndex: Integer): TDetailBGLNode;
begin
  Result := TDetailBGLNode(FDetailBGLs.Items[AIndex]);
end;

function TGclNode.GetDetailBGLCount: Integer;
begin
  Result := FDetailBGLs.Count;
end;

function TGclNode.GetDetailDeal(AIndex: Integer): TDetailDealNode;
begin
  Result := TDetailDealNode(FDetailDeals.Items[AIndex]);
end;

function TGclNode.GetDetailDealCount: Integer;
begin
  Result := FDetailDeals.Count;
end;

function TGclNode.GetDetailGcl(AIndex: Integer): TDetailGclNode;
begin
  Result := TDetailGclNode(FDetailGcls.Items[AIndex]);
end;

function TGclNode.GetDetailGclCount: Integer;
begin
  Result := FDetailGcls.Count;
end;

function TGclNode.GetLeafXmj(AIndex: Integer): TLeafXmjNode;
begin
  Result := TLeafXmjNode(FLeafXmjs.Items[AIndex]);
end;

function TGclNode.GetLeafXmjCount: Integer;
begin
  Result := FLeafXmjs.Count;
end;

procedure TGclNode.InitCalculate;
begin
  FOrgQuantity := 0;
  FOrgTotalPrice := 0;
  FMisQuantity := 0;
  FMisTotalPrice := 0;
  FOthQuantity := 0;
  FOthTotalPrice := 0;

  FQuantity := 0;
  FTotalPrice := 0;

  FCurDealQuantity := 0;
  FCurDealTotalPrice := 0;
  FCurQcQuantity := 0;
  FCurQcTotalPrice := 0;
  FCurGatherQuantity := 0;
  FCurGatherTotalPrice := 0;

  FPreDealQuantity := 0;
  FPreDealTotalPrice := 0;
  FPreQcQuantity := 0;
  FPreQcTotalPrice := 0;
  FPreGatherQuantity := 0;
  FPreGatherTotalPrice := 0;

  FEndDealQuantity := 0;
  FEndDealTotalPrice := 0;
  FEndQcQuantity := 0;
  FEndQcTotalPrice := 0;
  FEndGatherQuantity := 0;
  FEndGatherTotalPrice := 0;

  FAddDealQuantity := 0;
  FAddDealTotalPrice := 0;
  FAddQcQuantity := 0;
  FAddQcTotalPrice := 0;
  FAddGatherQuantity := 0;
  FAddGatherTotalPrice := 0;

  FDealQuantity := 0;
  FDealTotalPrice := 0;

  FBGLQuantity := 0;
  FBGLTotalPrice := 0;

  FDeal_BGLQuantity := 0;
  FDeal_BGLTotalPrice := 0;
  FDeal_BGLPercent := 0;
end;

procedure TGclNode.SetB_Code(const Value: string);
begin
  FB_Code := Value;
  FIndexCode := B_CodeToIndexCode(FB_Code);
end;

{ TDetailGclNode }

constructor TDetailGclNode.Create(AID: Integer);
begin
  FID := AID;
end;

function TDetailGclNode.GetPercent: Double;
var
  fTotal: Double;
begin
  fTotal := abs(FQuantity + FEndQcQuantity);
  if fTotal <> 0 then
    Result := CommonRoundTo(abs(FEndGatherQuantity) / fTotal * 100, -2)
  else
    Result := 0;
end;

{ TDetailBGLNode }

constructor TDetailBGLNode.Create(AID: Integer);
begin
  FID := AID;
end;

{ TDetailDealNode }

constructor TDetailDealNode.Create(AID: Integer);
begin
  FID := AID;
end;

{ TLeafXmjNode }

constructor TLeafXmjNode.Create(ALeafXmj, APeg: TBillsIDTreeNode);

  function GetPegName: string;
  begin
    if Assigned(APeg) then
      Result := APeg.Rec.Name.AsString
    else
      Result := '';
  end;

  // 取树结构的第ALevel层节点的名称（level从0开始）
  function GetNameByLevel(ANode: TBillsIDTreeNode; ALevel: Integer): string;
  begin
    Result := '';
    if not Assigned(ANode) then Exit;
    if ANode.Level = ALevel then
      Result := ANode.Rec.Name.AsString
    else if ANode.Level > ALevel then
      Result := GetNameByLevel(TBillsIDTreeNode(ANode.Parent), ALevel);
  end;

  function GetNameDanWei(ANode: TBillsIDTreeNode): string;
  begin
    // 取树结构的第二层节点的名称
    Result := GetNameByLevel(ANode, 1);
  end;

  // ANode为计量单元节点，APegNode为桩号节点
  function GetNameFenBu(ANode, APegNode: TBillsIDTreeNode): string;
  var
    vCurNode: TBillsIDTreeNode;
  begin
    // 如果计量单元节点的名称为桩号（转化为判断计量单元节点与桩号节点为同一个）
    if not Assigned(APegNode) or (ANode.ID = APegNode.ID) then
      // 取树结构的第三层节点的名称
      Result := GetNameByLevel(ANode, 2)
    // 否则，取桩号节点的子节点的名称
    else
    begin
      vCurNode := ANode;
      while vCurNode.Level > APegNode.Level + 1 do
        vCurNode := TBillsIDTreeNode(vCurNode.Parent);
      Result := vCurNode.Rec.Name.AsString;
    end;
  end;

  // ANode为计量单元节点，APegNode为桩号节点
  function GetNameFenXiang(ANode, APegNode: TBillsIDTreeNode): string;
  var
    iTopLevel: Integer;
    vCurNode: TBillsIDTreeNode;
  begin
    if Assigned(APegNode) then
    begin
      iTopLevel := 3;
      if APegNode.ID <> ANode.ID then
        iTopLevel := APegNode.Level + 2;
      Result := '';
      vCurNode := TBillsIDTreeNode(ANode.Parent);
      while vCurNode.Level >= iTopLevel do
      begin
        Result := vCurNode.Rec.Name.AsString + ';' + Result;
        vCurNode := TBillsIDTreeNode(vCurNode.Parent);
      end;
    end
    else
      Result := GetNameByLevel(ANode, 3);
  end;

  function GetNameUnit(ANode: TBillsIDTreeNode): string;
  begin
    Result := ANode.Rec.Name.AsString;
  end;

  function GetDrawingCode(ANode: TBillsIDTreeNode): string;
  begin
    Result := '';
    if not Assigned(ANode) then Exit;
    Result := ANode.Rec.DrawingCode.AsString;
    if Result = '' then
      Result := GetDrawingCode(TBillsIDTreeNode(ANode.Parent));
  end;

  function GetPosition(ANode, APegNode: TBillsIDTreeNode): string;
  begin
    // 如果计量单元节点的名称为桩号（转化为判断计量单元节点与桩号节点为同一个）
    if not Assigned(APegNode) or (ANode.ID = APegNode.ID) then
      // 取分部工程
      Result := GetNameFenXiang(ANode, APegNode)
    // 反之，取分项工程+计量单元
    else
      Result := GetNameFenXiang(ANode, APegNode) + GetNameUnit(ANode);
  end;

begin
  if not Assigned(ALeafXmj) then Exit;

  FID := ALeafXmj.ID;
  FXmjCode := ALeafXmj.Rec.Code.AsString;
  FXmjName := ALeafXmj.Rec.Name.AsString;
  FXmjUnits := ALeafXmj.Rec.Units.AsString;
  FPeg := GetPegName;
  FNameDanWei := GetNameDanWei(ALeafXmj);
  FNameFenBu := GetNameFenBu(ALeafXmj, APeg);
  FNameFenXiang := GetNameFenXiang(ALeafXmj, APeg);
  FNameUnit := GetNameUnit(ALeafXmj);
  FPosition := GetPosition(ALeafXmj, APeg);
  FDrawingCode := GetDrawingCode(ALeafXmj);
end;

end.
