unit OtherMeasurePhaseDm; interface uses CalcDecimal, SysUtils, Classes, sdDB, sdProvider, ADODB, OMPhaseRecord; type TOtherMeasurePhaseData = class(TDataModule) sdpPhase: TsdADOProvider; sddPhase: TsdDataSet; sdvPhase: TsdDataView; procedure sdvPhaseBeforeAddRecord(ARecord: TsdDataRecord; var Allow: Boolean); procedure sdvPhaseAfterValueChanged(AValue: TsdValue); procedure sddPhaseGetRecordClass(var ARecordClass: TsdRecordClass); procedure sddPhaseAfterValueChanged(AValue: TsdValue); procedure sdvPhaseSetText(var Text: String; ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn; var Allow: Boolean); procedure sdvPhaseBeforeDeleteRecord(ARecord: TsdDataRecord; var Allow: Boolean); procedure sdvPhaseFilterRecord(ARecord: TsdDataRecord; var Allow: Boolean); procedure sdvPhaseGetText(var Text: String; ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn; DisplayText: Boolean); private FProjectData: TObject; FFilterDeletedRec: Boolean; function GetNewID: Integer; function GetNewSerialNo: Integer; procedure SaveDetailData; procedure BeforeBatchOperation; procedure AfterBatchOperation; procedure SetFilterDeletedRec(const Value: Boolean); function GetDecimal: TCalcDecimal; public constructor Create(AProjectData: TObject); destructor Destroy; override; procedure Open(AConnection: TADOConnection); procedure Save; procedure LoadCurStageData; procedure CalculateAll; procedure CalculateRecord(ARec: TOMPhaseRecord); property Decimal: TCalcDecimal read GetDecimal; property FilterDeletedRec: Boolean read FFilterDeletedRec write SetFilterDeletedRec; end; implementation uses ProjectData, UtilMethods, Math, DB; {$R *.dfm} { TOtherMeasurePhaseData } procedure TOtherMeasurePhaseData.AfterBatchOperation; begin sddPhase.EndUpdate; sddPhase.EnableControls; sddPhase.AfterValueChanged := sddPhaseAfterValueChanged; end; procedure TOtherMeasurePhaseData.BeforeBatchOperation; begin sddPhase.AfterValueChanged := nil; sddPhase.DisableControls; sddPhase.BeginUpdate; end; constructor TOtherMeasurePhaseData.Create(AProjectData: TObject); begin inherited Create(nil); FProjectData := AProjectData; FFilterDeletedRec := True; end; destructor TOtherMeasurePhaseData.Destroy; begin inherited; end; function TOtherMeasurePhaseData.GetNewID: Integer; var idx: TsdIndex; begin idx := sddPhase.FindIndex('idxID'); if idx.RecordCount > 0 then Result := idx.Records[idx.RecordCount - 1].ValueByName('ID').AsInteger + 1 else Result := 1; end; function TOtherMeasurePhaseData.GetNewSerialNo: Integer; var idx: TsdIndex; begin idx := sddPhase.FindIndex('idxSerial'); if idx.RecordCount > 0 then Result := idx.Records[idx.RecordCount - 1].ValueByName('SerialNo').AsInteger + 1 else Result := 1; end; procedure TOtherMeasurePhaseData.LoadCurStageData; procedure LoadData; const sSelectSql = 'Select * From OMPhaseDetail Where (PhaseID = %d) and (StageID = %d)'; var vQuery: TADOQuery; i: Integer; Rec: TOMPhaseRecord; begin try with TProjectData(FProjectData) do vQuery := QueryData(sdpPhase.Connection, Format(sSelectSql, [PhaseIndex, StageIndex])); for i := 0 to sddPhase.RecordCount - 1 do begin Rec := TOMPhaseRecord(sddPhase.Records[i]); if vQuery.Locate('ID', Rec.ValueByName('ID').AsInteger, []) then begin Rec.PreTotalPrice.AsFloat := vQuery.FieldByName('PreTotalPrice').AsFloat; Rec.CurTotalPrice.AsFloat := vQuery.FieldByName('CurTotalPrice').AsFloat; Rec.EndTotalPrice.AsFloat := vQuery.FieldByName('EndTotalPrice').AsFloat; end else begin Rec.PreTotalPrice.AsFloat := 0; Rec.CurTotalPrice.AsFloat := 0; Rec.EndTotalPrice.AsFloat := 0; end; end; finally vQuery.Free; end; end; begin BeforeBatchOperation; try LoadData; finally AfterBatchOperation; end; end; procedure TOtherMeasurePhaseData.Open(AConnection: TADOConnection); begin sdpPhase.Connection := AConnection; sddPhase.Open; if not Assigned(sddPhase.FindIndex('idxID')) then sddPhase.AddIndex('idxID', 'ID'); if not Assigned(sddPhase.FindIndex('idxSerial')) then sddPhase.AddIndex('idxSerial', 'SerialNo'); sdvPhase.Open; sdvPhase.IndexName := 'idxSerial'; sdvPhase.Filtered := True; LoadCurStageData; end; procedure TOtherMeasurePhaseData.Save; begin sddPhase.Save; if not TProjectData(FProjectData).StageDataReadOnly then SaveDetailData; end; procedure TOtherMeasurePhaseData.SaveDetailData; const sClearSql = 'Delete From OMPhaseDetail where ID not in (Select distinct ID From OtherMeasurePhase)'; sDeleteSql = 'Delete From OMPhaseDetail where (PhaseID = %d) and (StageID = %d)'; sInsertSql = 'Insert Into OMPhaseDetail' + ' Select ID, %d As PhaseID, %d As StageID, PreTotalPrice, CurTotalPrice, EndTotalPrice' + ' From OtherMeasurePhase Where not Deleted'; var iPhase, iStage: Integer; vQuery: TADOQuery; begin if TProjectData(FProjectData).StageDataReadOnly then Exit; // 被删除的数据,也不应保留明细 ExecuteSql(sdpPhase.Connection, sClearSql); iPhase := TProjectData(FProjectData).PhaseIndex; iStage := TProjectData(FProjectData).StageIndex; ExecuteSql(sdpPhase.Connection, Format(sDeleteSql, [iPhase, iStage])); ExecuteSql(sdpPhase.Connection, Format(sInsertSql, [iPhase, iStage])); ExecuteSql(sdpPhase.Connection, Format(sDeleteSql, [iPhase, -1])); ExecuteSql(sdpPhase.Connection, Format(sInsertSql, [iPhase, -1])); end; procedure TOtherMeasurePhaseData.sdvPhaseBeforeAddRecord( ARecord: TsdDataRecord; var Allow: Boolean); begin ARecord.ValueByName('ID').AsInteger := GetNewID; ARecord.ValueByName('SerialNo').AsInteger := GetNewSerialNo; ARecord.ValueByName('CreatePhaseID').AsInteger := TProjectData(FProjectData).PhaseIndex; ARecord.ValueByName('CreateStageID').AsInteger := TProjectData(FProjectData).StageIndex; end; procedure TOtherMeasurePhaseData.sdvPhaseAfterValueChanged( AValue: TsdValue); var Rec: TOMPhaseRecord; begin if SameText(AValue.FieldName, 'CurTotalPrice') then begin Rec := TOMPhaseRecord(AValue.Owner); Rec.SetFloatValue(Rec.EndTotalPrice, TotalPriceRoundTo(Rec.CurTotalPrice.AsFloat + Rec.PreTotalPrice.AsFloat)); end; end; procedure TOtherMeasurePhaseData.sddPhaseGetRecordClass( var ARecordClass: TsdRecordClass); begin ARecordClass := TOMPhaseRecord; end; procedure TOtherMeasurePhaseData.sddPhaseAfterValueChanged( AValue: TsdValue); var Rec: TOMPhaseRecord; begin if SameText(AValue.FieldName, 'CurTotalPrice') then begin Rec := TOMPhaseRecord(AValue.Owner); Rec.SetFloatValue(Rec.EndTotalPrice, TotalPriceRoundTo(Rec.CurTotalPrice.AsFloat + Rec.PreTotalPrice.AsFloat)); Rec.SetFloatValue(Rec.AddTotalPrice, Rec.EndTotalPrice.AsFloat); end; end; procedure TOtherMeasurePhaseData.sdvPhaseSetText(var Text: String; ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn; var Allow: Boolean); begin if SameText(AColumn.FieldName, 'Code') then begin if (Text = '') then begin if (ARecord.ValueByName('Name').AsString = '') then DataSetErrorMessage(Allow, '编号和名称不可同时为空。'); if (ARecord.ValueByName('Code').AsString = '') and (ARecord.ValueByName('Name').AsString = '') then sddPhase.Remove(ARecord); end; end else if SameText(AColumn.FieldName, 'Name') then begin if (Text = '') then begin if (ARecord.ValueByName('Code').AsString = '') then DataSetErrorMessage(Allow, '编号和名称不可同时为空。'); if(ARecord.ValueByName('Code').AsString = '') and (ARecord.ValueByName('Name').AsString = '') then sddPhase.Remove(ARecord); end; end else begin if (ARecord.ValueByName('Code').AsString = '') and (ARecord.ValueByName('Name').AsString = '') then begin DataSetErrorMessage(Allow, '编号、名称不可同时为空,请先填写编号或名称,再填写其他信息。'); sddPhase.Remove(AValue.Owner); end else if Pos('TotalPrice', AColumn.FieldName) > 0 then Text := FloatToStr(Decimal.TotalPrice.RoundTo(StrToFloatDef(Text, 0))); end; end; procedure TOtherMeasurePhaseData.sdvPhaseBeforeDeleteRecord( ARecord: TsdDataRecord; var Allow: Boolean); function CanDelete(ARec: TsdDataRecord): Boolean; begin Result := (ARec.ValueByName('CreatePhaseID').AsInteger = TProjectData(FProjectData).PhaseIndex) and (ARec.ValueByName('CreateStageID').AsInteger = TProjectData(FProjectData).StageIndex); end; begin Allow := CanDelete(ARecord); if not Allow then begin ARecord.ValueByName('Deleted').AsBoolean := True; ARecord.ValueByName('DeletePhaseID').AsInteger := TProjectData(FProjectData).PhaseIndex; ARecord.ValueByName('DeleteStageID').AsInteger := TProjectData(FProjectData).StageIndex; sdvPhase.RefreshFilter; end; end; procedure TOtherMeasurePhaseData.sdvPhaseFilterRecord( ARecord: TsdDataRecord; var Allow: Boolean); begin if Assigned(ARecord) then Allow := not ARecord.ValueByName('Deleted').AsBoolean; end; procedure TOtherMeasurePhaseData.SetFilterDeletedRec(const Value: Boolean); begin FFilterDeletedRec := Value; sdvPhase.Filtered := FFilterDeletedRec; end; procedure TOtherMeasurePhaseData.sdvPhaseGetText(var Text: String; ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn; DisplayText: Boolean); procedure GetDisplayText; begin if AValue.DataType = ftFloat then if AValue.AsFloat = 0 then Text := ''; end; begin if DisplayText then GetDisplayText; end; function TOtherMeasurePhaseData.GetDecimal: TCalcDecimal; begin Result := TProjectData(FProjectData).ProjProperties.DecimalManager.Common; end; procedure TOtherMeasurePhaseData.CalculateAll; var i: Integer; Rec: TOMPhaseRecord; begin for i := 0 to sddPhase.RecordCount - 1 do begin Rec := TOMPhaseRecord(sddPhase.Records[i]); CalculateRecord(Rec); end; end; procedure TOtherMeasurePhaseData.CalculateRecord(ARec: TOMPhaseRecord); begin ARec.SetFloatValue(ARec.EndTotalPrice, Decimal.TotalPrice.RoundTo(ARec.CurTotalPrice.AsFloat + ARec.PreTotalPrice.AsFloat)); ARec.SetFloatValue(ARec.AddTotalPrice, ARec.EndTotalPrice.AsFloat); end; end.