unit rmMentalCustomized1Dm;

// 工程量清单章级汇总表 -- 交叉表
// 先统计各项目中，各章级清单的金额，然后汇总
// 甘肃--高管局定制 -- 严禁任何其他项目使用该单元结果。

interface

uses
  SysUtils, Classes, DB, DBClient, ZhAPI, rmSelectProjectFrm,
  ProjectData, sdDB, UtilMethods, sdIDTree;

type
  {Custom1}
  TTP_Record = record
    FTotalPrice: Double;
    FAddQcTotalPrice: Double;
    FAddGatherTotalPrice: Double;
  end;

  TChapterGcl = array [1..9] of Double;

  TProjectChapterGcl = class
  private
    FProjectName: string;
    FTotalPrice: TChapterGcl;
    FAddQcTotalPrice: TChapterGcl;
    FAddGatherTotalPrice: TChapterGcl;

    function GetTotalPrice(AIndex: Integer): Double;
    procedure SetTotalPrice(AIndex: Integer; const Value: Double);
    function GetAddGatherTotalPrice(AIndex: Integer): Double;
    function GetAddQcTotalPrice(AIndex: Integer): Double;
    procedure SetAddGatherTotalPrice(AIndex: Integer; const Value: Double);
    procedure SetAddQcTotalPrice(AIndex: Integer; const Value: Double);
    function GetCompletePercent(AIndex: Integer): Double;

    function GetChapterTotal: Double;
    function GetTempTotal: Double;
    function GetBidPrice: Double;

    function GetAG_ChapterTotal: Double;
    function GetAG_TempTotal: Double;
    function GetAG_BidPrice: Double;

    function GetAQ_ChapterTotal: Double;
    function GetAQ_TempTotal: Double;
    function GetAQ_BidPrice: Double;

    function GetCT_CompletePercent: Double;
    function GetBP_CompletePercent: Double;
    function GetTT_CompletePercent: Double;
  public
    constructor Create(const AProjectName: string);

    property ProjectName: string read FProjectName;
    property TotalPrice[AIndex: Integer]: Double read GetTotalPrice write SetTotalPrice;
    property AddQcTotalPrice[AIndex: Integer]: Double read GetAddQcTotalPrice write SetAddQcTotalPrice;
    property AddGatherTotalPrice[AIndex: Integer]: Double read GetAddGatherTotalPrice write SetAddGatherTotalPrice;
    property CompletePercent[AIndex: Integer]: Double read GetCompletePercent;

    property ChapterTotal: Double read GetChapterTotal;
    property TempTotal: Double read GetTempTotal;
    property BidPrice: Double read GetBidPrice;

    property AQ_ChapterTotal: Double read GetAQ_ChapterTotal;
    property AQ_TempTotal: Double read GetAQ_TempTotal;
    property AQ_BidPrice: Double read GetAQ_BidPrice;

    property AG_ChapterTotal: Double read GetAG_ChapterTotal;
    property AG_TempTotal: Double read GetAG_TempTotal;
    property AG_BidPrice: Double read GetAG_BidPrice;

    property CT_CompletePercent: Double read GetCT_CompletePercent;
    property TT_CompletePercent: Double read GetTT_CompletePercent;
    property BP_CompletePercent: Double read GetBP_CompletePercent;
  end;

  TChapterGather = class
  private
    FProjectsChapter: TList;
    FTotalChapter: TProjectChapterGcl;
  public
    constructor Create;
    destructor Destroy; override;

    function AddProjectChapterGcl(const AProjectName: string): TProjectChapterGcl;

    procedure CalcTotal;
  end;

  {Custom2}
  TTender = class
  private
    FTenderName: string;
    FTotalPrice: Double;
    FEndGatherTotalPrice: Double;
    function GetPercent: Double;
  public
    constructor Create(ATenderName: string);

    property TenderName: string read FTenderName;
    property TotalPrice: Double read FTotalPrice write FTotalPrice;
    property EndGatherTotalPrice: Double read FEndGatherTotalPrice write FEndGatherTotalPrice;
    property Percent: Double read GetPercent;
  end;

  TTenderClass = class
  private
    FClassName: string;
    FTenders: TList;
    function GetPercent: Double;
    function GetTotalPrice: Double;
    function GetEndGatherTotalPrice: Double;
  public
    constructor Create(const AClassName: string);
    destructor Destroy; override;

    function AddTender(const ATenderName: string): TTender;

    property TotalPrice: Double read GetTotalPrice;
    property EndGatherTotalPrice: Double read GetEndGatherTotalPrice;
    property Percent: Double read GetPercent;
  end;

  TTenderClassList = class
  private
    FClassList: TList;

    function FindTenderClass(const AClassName: string): TTenderClass;
    function AddTenderClass(const AClassName: string): TTenderClass;
  public
    constructor Create;
    destructor Destroy; override;

    function TenderClass(const AClassName: string): TTenderClass;
  end;

  TrmMentalCustomized1Data = class(TDataModule)
    // 格式1
    cdsCustom1: TClientDataSet;
    cdsCustom1ProjectID: TIntegerField;
    cdsCustom1ProjectName: TWideStringField;
    cdsCustom1SerialNo: TIntegerField;
    cdsCustom1ChapterID: TWideStringField;
    cdsCustom1ChapterName: TWideStringField;
    cdsCustom1P_TotalPrice: TFloatField;
    cdsCustom1P_AddQcTotalPrice: TFloatField;
    cdsCustom1P_AddGatherTotalPrice: TFloatField;
    cdsCustom1P_Percent: TFloatField;
    cdsCustom1TotalPrice: TFloatField;
    cdsCustom1AddQcTotalPrice: TFloatField;
    cdsCustom1AddGatherTotalPrice: TFloatField;
    cdsCustom1Percent: TFloatField;
    // 格式2
    cdsCustom2: TClientDataSet;
    cdsCustom2ClassID: TIntegerField;
    cdsCustom2SerialNo: TFloatField;
    cdsCustom2ClassName: TWideStringField;
    cdsCustom2TenderName: TWideStringField;
    cdsCustom2TotalPrice: TFloatField;
    cdsCustom2EndGatherTotalPrice: TFloatField;
    cdsCustom2Percent: TFloatField;
  private
    FMentalType: Integer;
    // Custom1
    FChapterGather: TChapterGather;
    FProjectData: TProjectData;
    // Custom2
    FClasses: TTenderClassList;
    FWriteSerilaNo: Integer;

    procedure BeforeGather(AProjects: TList);
    procedure AfterGather;

    function OpenProjectData(AProject: TSelectProject): TProjectChapterGcl;
    procedure FreeProjectData;

    function XmjNode(const ACode: string): TsdIDTreeNode;
    // 汇总项目节ACode下的所有起始编号为AChapterID的清单金额
    function ChapterTotalPrice(const ACode: string; AChapterID: string = ''): TTP_Record;

    function B_CodeToChapter(const AB_Code: string): Integer;
    procedure GatherGclChapter(AProjectChapter: TProjectChapterGcl);
    procedure GatherProject(AProject: TSelectProject);

    function TenderClassName(AProjectID: Integer): string;
    procedure GatherTenderMainData(AProject: TSelectProject);

    procedure CalcuateGather;
    procedure GatherData(AProjects: TList);

    procedure WriteProjectChapter(AProjectID: Integer; AProject, ATotal: TProjectChapterGcl);
    procedure WriteCustomized0;

    procedure WriteTenderClass(AClassID: Integer; ATenderClass: TTenderClass);
    procedure WriteCustomized1;

    procedure WriteData;
  public
    function AssignData(AProjects: TList): TDataSet;

    property MentalType: Integer read FMentalType write FMentalType;
  end;

implementation

uses
  BillsDm, mDataRecord, Globals, Windows;

{$R *.dfm}

{ TrmGclChapterGatherData }

procedure TrmMentalCustomized1Data.AfterGather;
begin
  FChapterGather.Free;
  cdsCustom1.EnableControls;
  cdsCustom1.IndexFieldNames := 'ProjectID;SerialNo';

  FClasses.Free;
  cdsCustom2.EnableControls;
end;

function TrmMentalCustomized1Data.AssignData(AProjects: TList): TDataSet;
var
  iProject: Integer;
  SelectProject: TSelectProject;
begin
  BeforeGather(AProjects);
  try
    GatherData(AProjects);
    WriteData;
  finally
    case FMentalType of
      0: Result := cdsCustom1;
      1: Result := cdsCustom2;
    end;
    AfterGather;
  end;
end;

procedure TrmMentalCustomized1Data.BeforeGather(AProjects: TList);
begin
  cdsCustom1.DisableControls;
  cdsCustom1.Active := True;
  cdsCustom1.EmptyDataSet;
  FChapterGather := TChapterGather.Create;

  cdsCustom2.DisableControls;
  cdsCustom2.Active := True;
  cdsCustom2.EmptyDataSet;
  FClasses := TTenderClassList.Create;
end;

function TrmMentalCustomized1Data.B_CodeToChapter(
  const AB_Code: string): Integer;
var
  sgs: TStrings;
  iFirst, iSecond: Integer;
begin
  Result := 0;
  sgs := TStringList.Create;
  try
    sgs.Delimiter := '-';
    sgs.DelimitedText := AB_Code;
    iFirst := StrToIntDef(sgs.Strings[0], 0);
    // X,M表示1-9，其中XMM-M与M-XMM-M同属X章级
    if (iFirst < 99) and (sgs.Count > 1) then
    begin
      iSecond := StrToIntDef(sgs.Strings[1], 0);
      Result := Trunc(iSecond/100);
    end
    else
      Result := Trunc(iFirst/100);
  finally
    sgs.Free;
  end;
end;

procedure TrmMentalCustomized1Data.CalcuateGather;
begin
  if FMentalType = 0 then
    FChapterGather.CalcTotal;
end;

function TrmMentalCustomized1Data.ChapterTotalPrice(const ACode: string;
  AChapterID: string): TTP_Record;
var
  stnNode, stnChild: TsdIDTreeNode;
  iNext, iTotal: Integer;
begin 
  Result.FTotalPrice := 0;
  Result.FAddQcTotalPrice := 0;
  Result.FAddGatherTotalPrice := 0;
  stnNode := XmjNode(ACode);
  if not Assigned(stnNode) then Exit;
  
  stnChild := stnNode.FirstChild;
  iNext := 1;
  iTotal := stnNode.PosterityCount;
  while iNext <= iTotal do
  begin
    with TBillsRecord(stnChild.Rec) do
      if not stnChild.HasChildren and (B_Code.AsString <> '') then
        if (AChapterID = '') or (Pos(AChapterID, Trim(B_Code.AsString)) = 1) then
        begin
          Result.FTotalPrice := Result.FTotalPrice + TotalPrice.AsFloat;
          Result.FAddQcTotalPrice := Result.FAddQcTotalPrice + AddQcTotalPrice.AsFloat;
          Result.FAddGatherTotalPrice := Result.FAddGatherTotalPrice + AddGatherTotalPrice.AsFloat;
        end;

    Inc(iNext);
    stnChild := stnChild.NextNode;
  end;
end;

procedure TrmMentalCustomized1Data.FreeProjectData;
begin
  if not Assigned(OpenProjectManager.FindProjectData(FProjectData.ProjectID)) then
    FProjectData.Free;
end;

procedure TrmMentalCustomized1Data.GatherData(AProjects: TList);
var
  iProject: Integer;
begin
  for iProject := 0 to AProjects.Count - 1 do
    if MentalType = 0 then
      GatherProject(TSelectProject(AProjects.Items[iProject]))
    else
      GatherTenderMainData(TSelectProject(AProjects.Items[iProject]));
  CalcuateGather;
end;

procedure TrmMentalCustomized1Data.GatherGclChapter(
  AProjectChapter: TProjectChapterGcl);

  procedure GatherChapter(AChapterID: Integer; const ACode: string; ASearchChapter: string = '');
  var
    CalcRecord: TTP_Record;
  begin
    CalcRecord := ChapterTotalPrice(ACode, ASearchChapter);

    AProjectChapter.TotalPrice[AChapterID] :=
      AProjectChapter.TotalPrice[AChapterID] + CalcRecord.FTotalPrice;
    AProjectChapter.AddQcTotalPrice[AChapterID] :=
      AProjectChapter.AddQcTotalPrice[AChapterID] + CalcRecord.FAddQcTotalPrice;
    AProjectChapter.AddGatherTotalPrice[AChapterID] :=
      AProjectChapter.AddGatherTotalPrice[AChapterID] + CalcRecord.FAddGatherTotalPrice;
  end;

begin
  // 1-1下的全部清单为100章
  GatherChapter(1, '1-1', '');
  // 1-2下的全部清单为200章
  GatherChapter(2, '1-2', '');
  // 1-3下的全部清单为300章
  GatherChapter(3, '1-3', '');
  // 1-4下的全部清单为400章
  GatherChapter(4, '1-4', '');
  // 1-5、1-6下的全部清单为500章
  GatherChapter(5, '1-5', '');
  GatherChapter(5, '1-6', '');
  // 1-7下【清单编号以6开头】的全部清单为600章
  GatherChapter(6, '1-7', '6');
  // 1-7下【清单编号以2、8开头】的全部清单为600章
  GatherChapter(8, '1-7', '2');
  GatherChapter(8, '1-7', '8');
  // 1-8下的全部清单为800章
  GatherChapter(7, '1-8', '');
  // 1-9下的全部清单为900章
  GatherChapter(9, '1-9', '');
end;

procedure TrmMentalCustomized1Data.GatherProject(AProject: TSelectProject);
var
  ProjectChapter: TProjectChapterGcl;
begin
  ProjectChapter := OpenProjectData(AProject);
  try
    GatherGclChapter(ProjectChapter);
  finally
    FreeProjectData;
  end;
end;

procedure TrmMentalCustomized1Data.GatherTenderMainData(
  AProject: TSelectProject);
var
  TenderClass: TTenderClass;
  Rec: TsdDataRecord;
  Tender: TTender;
begin
  TenderClass := FClasses.TenderClass(TenderClassName(AProject.ProjectID));
  Rec := ProjectManager.sddProjectsInfo.FindKey('idxID', AProject.ProjectID);
  Tender := TenderClass.AddTender(Rec.ValueByName('Name').AsString);
  Tender.TotalPrice := Rec.ValueByName('DealTotalPrice').AsFloat;
  Tender.EndGatherTotalPrice := Rec.ValueByName('EndTotalPrice').AsFloat;
end;

function TrmMentalCustomized1Data.OpenProjectData(
  AProject: TSelectProject): TProjectChapterGcl;
var
  Rec: TsdDataRecord;
begin
  FProjectData := OpenProjectManager.FindProjectData(AProject.ProjectID);
  Rec := ProjectManager.sddProjectsInfo.FindKey('idxID', AProject.ProjectID);
  if not Assigned(FProjectData) then
  begin
    FProjectData := TProjectData.Create;
    FProjectData.OpenForReport(GetMyProjectsFilePath + Rec.ValueByName('FileName').AsString);
  end;
  Result := FChapterGather.AddProjectChapterGcl(Rec.ValueByName('Name').AsString);
end;

function TrmMentalCustomized1Data.TenderClassName(
  AProjectID: Integer): string;
var
  vNode: TsdIDTreeNode;
begin
  Result := '';
  vNode := ProjectManager.ProjectsTree.FindNode(AProjectID);
  if not Assigned(vNode) then Exit;

  while Assigned(vNode.Parent) do
    vNode := vNode.Parent;
  Result := vNode.Rec.ValueByName('Name').AsString;
end;

procedure TrmMentalCustomized1Data.WriteCustomized0;
var
  iProject: Integer;
  ProjectChapter: TProjectChapterGcl;
begin
  for iProject := 0 to FChapterGather.FProjectsChapter.Count - 1 do
  begin
    ProjectChapter := TProjectChapterGcl(FChapterGather.FProjectsChapter.Items[iProject]);
    WriteProjectChapter(iProject, ProjectChapter, FChapterGather.FTotalChapter);
  end;
end;

procedure TrmMentalCustomized1Data.WriteCustomized1;
var
  iClass: Integer;
begin
  FWriteSerilaNo := 1;
  for iClass := 0 to FClasses.FClassList.Count - 1 do
    WriteTenderClass(iClass, TTenderClass(FClasses.FClassList.Items[iClass]));
end;

procedure TrmMentalCustomized1Data.WriteData;
begin
  case FMentalType of
    0: WriteCustomized0;
    1: WriteCustomized1;
  end;
end;

procedure TrmMentalCustomized1Data.WriteProjectChapter(
  AProjectID: Integer; AProject, ATotal: TProjectChapterGcl);
const
  SChapterID: array [1..12] of string = ('100', '200', '300', '400',
    '500', '600', '700', '800', '900', '', '', '');
  SChapterName: array [1..12] of string = ('总则', '路基', '路面', '桥梁、涵洞',
    '隧道', '安全设施及预埋管线', '绿化及环境保护', '机电工程', '房建', '100章至900章清单合计 A', '暂列金额 B=A*10%', '投标价 C=A+B');

  procedure AddProjectChapter(AIndex: Integer);
  begin
    cdsCustom1.Append;
    cdsCustom1ProjectID.AsInteger := AProjectID;
    cdsCustom1ProjectName.AsString := AProject.FProjectName;
    cdsCustom1SerialNo.AsInteger := AIndex;
    cdsCustom1ChapterID.AsString := SChapterID[AIndex];
    cdsCustom1ChapterName.AsString := SChapterName[AIndex];
    cdsCustom1P_TotalPrice.AsFloat := AProject.TotalPrice[AIndex];
    cdsCustom1P_AddQcTotalPrice.AsFloat := AProject.AddQcTotalPrice[AIndex];
    cdsCustom1P_AddGatherTotalPrice.AsFloat := AProject.AddGatherTotalPrice[AIndex];
    cdsCustom1P_Percent.AsFloat := AProject.CompletePercent[AIndex];
    cdsCustom1TotalPrice.AsFloat := ATotal.TotalPrice[AIndex];
    cdsCustom1AddQcTotalPrice.AsFloat := ATotal.AddQcTotalPrice[AIndex];
    cdsCustom1AddGatherTotalPrice.AsFloat := ATotal.AddGatherTotalPrice[AIndex];
    cdsCustom1Percent.AsFloat := ATotal.CompletePercent[AIndex];
    cdsCustom1.Post;
  end;

  procedure AddProjectChapterTotal(AIndex: Integer);
  begin
    cdsCustom1.Append;
    cdsCustom1ProjectID.AsInteger := AProjectID;
    cdsCustom1ProjectName.AsString := AProject.FProjectName; 
    cdsCustom1SerialNo.AsInteger := AIndex;
    cdsCustom1ChapterID.AsString := SChapterID[AIndex];
    cdsCustom1ChapterName.AsString := SChapterName[AIndex];
    cdsCustom1P_TotalPrice.AsFloat := AProject.ChapterTotal;
    cdsCustom1P_AddQcTotalPrice.AsFloat := AProject.AQ_ChapterTotal;
    cdsCustom1P_AddGatherTotalPrice.AsFloat := AProject.AG_ChapterTotal;
    cdsCustom1P_Percent.AsFloat := AProject.CT_CompletePercent;
    cdsCustom1TotalPrice.AsFloat := ATotal.ChapterTotal;
    cdsCustom1AddQcTotalPrice.AsFloat := ATotal.AQ_ChapterTotal;
    cdsCustom1AddGatherTotalPrice.AsFloat := ATotal.AG_ChapterTotal;
    cdsCustom1Percent.AsFloat := ATotal.CT_CompletePercent;
    cdsCustom1.Post;
  end;

  procedure AddProjectTempTotal(AIndex: Integer);
  begin
    cdsCustom1.Append;
    cdsCustom1ProjectID.AsInteger := AProjectID;
    cdsCustom1ProjectName.AsString := AProject.FProjectName;
    cdsCustom1SerialNo.AsInteger := AIndex; 
    cdsCustom1ChapterID.AsString := SChapterID[AIndex];
    cdsCustom1ChapterName.AsString := SChapterName[AIndex];
    cdsCustom1P_TotalPrice.AsFloat := AProject.TempTotal;
    cdsCustom1P_AddQcTotalPrice.AsFloat := AProject.AQ_TempTotal;
    cdsCustom1P_AddGatherTotalPrice.AsFloat := AProject.AG_TempTotal;
    cdsCustom1P_Percent.AsFloat := AProject.TT_CompletePercent;
    cdsCustom1TotalPrice.AsFloat := ATotal.TempTotal;
    cdsCustom1AddQcTotalPrice.AsFloat := ATotal.AQ_TempTotal;
    cdsCustom1AddGatherTotalPrice.AsFloat := ATotal.AG_TempTotal;
    cdsCustom1Percent.AsFloat := ATotal.TT_CompletePercent;
    cdsCustom1.Post;
  end;

  procedure AddProjectBidPrice(AIndex: Integer);
  begin
    cdsCustom1.Append;
    cdsCustom1ProjectID.AsInteger := AProjectID;
    cdsCustom1ProjectName.AsString := AProject.FProjectName;
    cdsCustom1SerialNo.AsInteger := AIndex; 
    cdsCustom1ChapterID.AsString := SChapterID[AIndex];
    cdsCustom1ChapterName.AsString := SChapterName[AIndex];
    cdsCustom1P_TotalPrice.AsFloat := AProject.BidPrice;
    cdsCustom1P_AddQcTotalPrice.AsFloat := AProject.AQ_BidPrice;
    cdsCustom1P_AddGatherTotalPrice.AsFloat := AProject.AG_BidPrice;
    cdsCustom1P_Percent.AsFloat := AProject.BP_CompletePercent;
    cdsCustom1TotalPrice.AsFloat := ATotal.BidPrice;
    cdsCustom1AddQcTotalPrice.AsFloat := ATotal.AQ_BidPrice;
    cdsCustom1AddGatherTotalPrice.AsFloat := ATotal.AG_BidPrice;
    cdsCustom1Percent.AsFloat := ATotal.BP_CompletePercent;
    cdsCustom1.Post;
  end;

var
  iIndex: Integer;
begin
  for iIndex := Low(TChapterGcl) to High(TChapterGcl) do
    AddProjectChapter(iIndex);
  AddProjectChapterTotal(10);
  AddProjectTempTotal(11);
  AddProjectBidPrice(12);
end;

{ TProjectChapterGcl }

constructor TProjectChapterGcl.Create(const AProjectName: string);
begin
  FProjectName := AProjectName;
  ZeroMemory(@FTotalPrice, SizeOf(TChapterGcl));
  ZeroMemory(@FAddQcTotalPrice, SizeOf(TChapterGcl));
  ZeroMemory(@FAddGatherTotalPrice, SizeOf(TChapterGcl));
end;

function TProjectChapterGcl.GetAddGatherTotalPrice(
  AIndex: Integer): Double;
begin
  Result := FAddGatherTotalPrice[AIndex];
end;

function TProjectChapterGcl.GetAddQcTotalPrice(AIndex: Integer): Double;
begin
  Result := FAddQcTotalPrice[AIndex];
end;

function TProjectChapterGcl.GetAG_BidPrice: Double;
begin
  Result := AG_ChapterTotal + AG_TempTotal;
end;

function TProjectChapterGcl.GetAG_ChapterTotal: Double;
var
  i: Integer;
begin
  Result := 0;
  for i := Low(TChapterGcl) to High(TChapterGcl) do
    Result := Result + FAddGatherTotalPrice[i];
end;

function TProjectChapterGcl.GetAG_TempTotal: Double;
begin
  Result := AG_ChapterTotal * 0.1;
end;

function TProjectChapterGcl.GetAQ_BidPrice: Double;
begin
  Result := AQ_ChapterTotal + AQ_TempTotal;
end;

function TProjectChapterGcl.GetAQ_ChapterTotal: Double;
var
  i: Integer;
begin
  Result := 0;
  for i := Low(TChapterGcl) to High(TChapterGcl) do
    Result := Result + FAddQcTotalPrice[i];
end;

function TProjectChapterGcl.GetAQ_TempTotal: Double;
begin
  Result := AQ_ChapterTotal * 0.1;
end;

function TProjectChapterGcl.GetBidPrice: Double;
begin
  Result := ChapterTotal + TempTotal;
end;

function TProjectChapterGcl.GetBP_CompletePercent: Double;
begin
  if (BidPrice + AQ_BidPrice) <> 0 then
    Result := AG_BidPrice/(BidPrice + AQ_BidPrice)*100
  else
    Result := 0;
end;

function TProjectChapterGcl.GetChapterTotal: Double;
var
  i: Integer;
begin
  Result := 0;
  for i := Low(TChapterGcl) to High(TChapterGcl) do
    Result := Result + FTotalPrice[i];
end;

function TProjectChapterGcl.GetCompletePercent(AIndex: Integer): Double;
begin
  if (FTotalPrice[AIndex] + FAddQcTotalPrice[AIndex]) <> 0 then
    Result := FAddGatherTotalPrice[AIndex]/(FTotalPrice[AIndex] + FAddQcTotalPrice[AIndex])*100
  else
    Result := 0;
end;

function TProjectChapterGcl.GetCT_CompletePercent: Double;
begin
  if (ChapterTotal + AQ_ChapterTotal) <> 0 then
    Result := AG_ChapterTotal/(ChapterTotal + AQ_ChapterTotal)*100
  else
    Result := 0;
end;

function TProjectChapterGcl.GetTempTotal: Double;
begin
  Result := ChapterTotal * 0.1;
end;

function TProjectChapterGcl.GetTotalPrice(AIndex: Integer): Double;
begin
  Result := FTotalPrice[AIndex];
end;

function TProjectChapterGcl.GetTT_CompletePercent: Double;
begin
  if (TempTotal + AQ_TempTotal) <> 0 then
    Result := AG_TempTotal/(TempTotal + AQ_TempTotal)*100
  else
    Result := 0;
end;

procedure TProjectChapterGcl.SetAddGatherTotalPrice(AIndex: Integer;
  const Value: Double);
begin
  FAddGatherTotalPrice[AIndex] := Value;
end;

procedure TProjectChapterGcl.SetAddQcTotalPrice(AIndex: Integer;
  const Value: Double);
begin
  FAddQcTotalPrice[AIndex] := Value;
end;

procedure TProjectChapterGcl.SetTotalPrice(AIndex: Integer;
  const Value: Double);
begin
  FTotalPrice[AIndex] := Value;
end;

{ TChapterGather }

function TChapterGather.AddProjectChapterGcl(
  const AProjectName: string): TProjectChapterGcl;
begin
  Result := TProjectChapterGcl.Create(AProjectName);
  FProjectsChapter.Add(Result);
end;

procedure TChapterGather.CalcTotal;
var
  iProject, iChapter: Integer;
  ProjectChapter: TProjectChapterGcl;
begin
  for iProject := 0 to FProjectsChapter.Count - 1 do
  begin
    ProjectChapter := TProjectChapterGcl(FProjectsChapter.Items[iProject]);
    for iChapter := Low(TChapterGcl) to High(TChapterGcl) do
    begin
      FTotalChapter.TotalPrice[iChapter] := FTotalChapter.TotalPrice[iChapter] + ProjectChapter.TotalPrice[iChapter];
      FTotalChapter.AddQcTotalPrice[iChapter] := FTotalChapter.AddQcTotalPrice[iChapter] + ProjectChapter.AddQcTotalPrice[iChapter];
      FTotalChapter.AddGatherTotalPrice[iChapter] := FTotalChapter.AddGatherTotalPrice[iChapter] + ProjectChapter.AddGatherTotalPrice[iChapter];
    end;
  end;
end;

constructor TChapterGather.Create;
begin
  FProjectsChapter := TList.Create;
  FTotalChapter := TProjectChapterGcl.Create('合计');
end;

destructor TChapterGather.Destroy;
begin
  FTotalChapter.Free;
  ClearObjects(FProjectsChapter);
  FProjectsChapter.Free;
  inherited;
end;

{ TTender }

constructor TTender.Create(ATenderName: string);
begin
  FTenderName := ATenderName;
end;

function TTender.GetPercent: Double;
begin
  if FTotalPrice <> 0 then
    Result := FEndGatherTotalPrice/FTotalPrice*100
  else
    Result := 0;
end;

{ TTenderClass }

function TTenderClass.AddTender(const ATenderName: string): TTender;
begin
  Result := TTender.Create(ATenderName);
  FTenders.Add(Result);
end;

constructor TTenderClass.Create(const AClassName: string);
begin
  FClassName := AClassName;
  FTenders := TList.Create;
end;

destructor TTenderClass.Destroy;
begin
  ClearObjects(FTenders);
  FTenders.Free;
  inherited;
end;

function TTenderClass.GetEndGatherTotalPrice: Double;
var
  i: Integer;
begin
  Result := 0;
  for i := 0 to FTenders.Count - 1 do
    Result := Result + TTender(FTenders.Items[i]).EndGatherTotalPrice;
end;

function TTenderClass.GetPercent: Double;
begin
  if TotalPrice <> 0 then
    Result := EndGatherTotalPrice/TotalPrice*100
  else
    Result := 0;
end;

function TTenderClass.GetTotalPrice: Double;
var
  i: Integer;
begin
  Result := 0;
  for i := 0 to FTenders.Count - 1 do
    Result := Result + TTender(FTenders.Items[i]).TotalPrice;
end;

{ TTenderClassList }

function TTenderClassList.AddTenderClass(
  const AClassName: string): TTenderClass;
begin
  Result := TTenderClass.Create(AClassName);
  FClassList.Add(Result);
end;

constructor TTenderClassList.Create;
begin
  FClassList := TList.Create;
end;

destructor TTenderClassList.Destroy;
begin
  ClearObjects(FClassList);
  FClassList.Free;
  inherited;
end;

function TTenderClassList.FindTenderClass(
  const AClassName: string): TTenderClass;
var
  iClass: Integer;
  TenderClass: TTenderClass;
begin
  Result := nil;
  for iClass := 0 to FClassList.Count - 1 do
  begin
    TenderClass := TTenderClass(FClassList.Items[iClass]);
    if SameText(AClassName, TenderClass.FClassName) then
    begin
      Result := TenderClass;
      Break;
    end;
  end;
end;

function TTenderClassList.TenderClass(
  const AClassName: string): TTenderClass;
begin
  Result := FindTenderClass(AClassName);
  if not Assigned(Result) then
    Result := AddTenderClass(AClassName);
end;

procedure TrmMentalCustomized1Data.WriteTenderClass(AClassID: Integer;
  ATenderClass: TTenderClass);

  procedure AddTenderRecord(ATender: TTender);
  begin
    cdsCustom2.Append;
    cdsCustom2ClassID.AsInteger := AClassID;
    cdsCustom2SerialNo.AsInteger := FWriteSerilaNo;
    cdsCustom2ClassName.AsString := ATenderClass.FClassName;
    cdsCustom2TenderName.AsString := ATender.TenderName;
    cdsCustom2TotalPrice.AsFloat := ATender.TotalPrice;
    cdsCustom2EndGatherTotalPrice.AsFloat := ATender.EndGatherTotalPrice;
    cdsCustom2Percent.AsFloat := ATender.Percent;
    cdsCustom2.Post;
    Inc(FWriteSerilaNo);
  end;

  procedure AddTotalRecord;
  begin
    cdsCustom2.Append;
    cdsCustom2ClassID.AsInteger := AClassID;
    cdsCustom2ClassName.AsString := '小计';
    cdsCustom2TotalPrice.AsFloat := ATenderClass.TotalPrice;
    cdsCustom2EndGatherTotalPrice.AsFloat := ATenderClass.EndGatherTotalPrice;
    cdsCustom2Percent.AsFloat := ATenderClass.Percent;
    cdsCustom2.Post;
  end;

var
  iTender: Integer;
begin
  for iTender := 0 to ATenderClass.FTenders.Count - 1 do
    AddTenderRecord(TTender(ATenderClass.FTenders.Items[iTender]));
  AddTotalRecord;
end;

function TrmMentalCustomized1Data.XmjNode(
  const ACode: string): TsdIDTreeNode;
var
  iID: Integer;
  Rec: TsdDataRecord;
begin
  Result := nil;
  Rec := FProjectData.BillsData.sddBills.Locate('Code', ACode);
  if Assigned(Rec) then
    Result := FProjectData.BillsCompileData.BillsCompileTree.FindNode(Rec.ValueByName('ID').AsInteger);
end;

end.
