Commit e56dc151 by Mac Stephens

Merge branch 'dev'

parents 21727feb 236fcdca
......@@ -13,6 +13,7 @@ emT3XDataServer/bin/static/
emT3XDataServer/Source/__history/
emT3XDataServer/Source/__recovery/
emT3XDataServer/Win32/
.validation/
*.exe
*.local
......
......@@ -22,7 +22,7 @@ type
public
currentTaskId: string;
currentTimeEntryDate: string;
const clientVersion = '0.9.3';
const clientVersion = '0.9.4.0';
procedure InitApp(SuccessProc: TSuccessProc;
UnauthorizedAccessProc: TUnauthorizedAccessProc);
procedure SetClientConfig(Callback: TVersionCheckCallback);
......
......@@ -58,6 +58,19 @@ object FTaskItems: TFTaskItems
WidthPercent = 100.000000000000000000
OnClick = btnInsertRowClick
end
object btnCopyRow: TWebButton
Left = 78
Top = 210
Width = 96
Height = 25
Caption = 'Copy Row'
Enabled = False
ElementID = 'btn_copy_row'
ElementFont = efCSS
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnCopyRowClick
end
object btnTextColor: TWebButton
Left = 282
Top = 197
......
......@@ -27,6 +27,7 @@
<button id="btn_add_row" class="btn btn-sm btn-success text-nowrap">Add Row</button>
<button id="btn_insert_row" class="btn btn-sm btn-success text-nowrap">Insert Row</button>
<button id="btn_copy_row" class="btn btn-sm btn-primary text-nowrap" disabled>Copy Row</button>
<button id="btn_delete_row" class="btn btn-sm btn-danger text-nowrap">Delete Row</button>
<button id="btn_reload" class="btn btn-sm btn-primary text-nowrap">Reload</button>
</div>
......
......@@ -31,6 +31,7 @@ type
xdwdsTaskstaskItemId: TIntegerField;
btnDeleteRow: TWebButton;
btnInsertRow: TWebButton;
btnCopyRow: TWebButton;
btnTextColor: TWebButton;
btnFmtBold: TWebButton;
btnFmtItalic: TWebButton;
......@@ -40,6 +41,7 @@ type
procedure WebFormCreate(Sender: TObject);
[async] procedure btnDeleteRowClick(Sender: TObject);
[async] procedure btnInsertRowClick(Sender: TObject);
[async] procedure btnCopyRowClick(Sender: TObject);
procedure btnTextColorClick(Sender: TObject);
procedure btnFmtBoldClick(Sender: TObject);
procedure btnFmtItalicClick(Sender: TObject);
......@@ -61,6 +63,8 @@ type
FActiveRichEditorId: string;
FLastSelectionRange: JSValue;
FNameManager: TNameManager;
FCopyingRow: Boolean;
[async] function CopyTaskRow: Boolean;
[async] procedure LoadTasks(const ATaskId: string);
procedure RenderTable;
procedure BindTableEditors;
......@@ -134,6 +138,8 @@ begin
FStatusOptions := TJSArray.new;
FSelectedTaskItemId := 0;
FSelectedTaskId := 0;
FCopyingRow := False;
btnCopyRow.Enabled := False;
FNameManager := TNameManager.Create(
function(const AFieldName: string): TJSArray
......@@ -465,6 +471,53 @@ begin
end;
end;
[async] procedure TFTaskItems.btnCopyRowClick(Sender: TObject);
begin
if FCopyingRow or (FSelectedTaskItemId <= 0) then
Exit;
FCopyingRow := True;
btnCopyRow.Enabled := False;
Utils.ShowSpinner('spinner');
try
if await(CopyTaskRow) then
begin
CaptureTableScroll;
await(LoadTasks(FTaskId));
end;
finally
FCopyingRow := False;
btnCopyRow.Enabled := FSelectedTaskItemId > 0;
Utils.HideSpinner('spinner');
end;
end;
[async] function TFTaskItems.CopyTaskRow: Boolean;
var
response: TXDataClientResponse;
sourceTaskItemId: Integer;
begin
Result := False;
sourceTaskItemId := FSelectedTaskItemId;
try
response := await(xdwcTasks.RawInvokeAsync(
'ITaskItemService.CopyTaskRow', [FTaskId, sourceTaskItemId]));
console.log('CopyTaskRow: response=' + string(TJSJSON.stringify(response.Result)));
FSelectedTaskItemId := StrToIntDef(string(TJSObject(response.Result)['value']), 0);
FPendingFocusTaskItemId := FSelectedTaskItemId;
FPendingFocusField := 'application';
Result := True;
except
on E: EXDataClientRequestException do
begin
console.log('CopyTaskRow ERROR: ' + E.ErrorResult.ErrorMessage);
Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
end;
end;
end;
procedure TFTaskItems.RowClick(Event: TJSEvent);
var
rowEl: TJSHTMLElement;
......@@ -488,6 +541,7 @@ end;
procedure TFTaskItems.ApplySelectedRowState;
begin
btnCopyRow.Enabled := (FSelectedTaskItemId > 0) and not FCopyingRow;
asm
const selectedTaskItemId = this.FSelectedTaskItemId;
document.querySelectorAll('.task-row-selectable').forEach(function(row){
......
......@@ -99,10 +99,10 @@ object FTimeEntries: TFTimeEntries
OnClick = btnSearchRangeClick
end
object btnCopyEntry: TWebButton
Left = 440
Top = 122
Width = 96
Height = 25
Left = 88
Top = 152
Width = 79
Height = 31
Caption = 'Copy'
ChildOrder = 7
ElementID = 'btn_copy_entry'
......
......@@ -3,6 +3,7 @@
<h5 class="mb-0 text-nowrap" id="lbl_time_entries_title"></h5>
<div class="d-flex align-items-center gap-2 ms-auto flex-nowrap">
<div id="lbl_time_total_hours" class="me-2 text-nowrap fw-semibold">Total Hours: 0</div>
<div id="lbl_time_total_rows" class="me-2 text-nowrap"></div>
<div class="d-flex align-items-center gap-2 flex-nowrap">
......@@ -72,13 +73,25 @@
<div id="task_picker_status" class="alert alert-danger py-1 px-2 mb-3 d-none small"></div>
<div class="d-flex justify-content-end gap-2">
<div class="d-flex align-items-center gap-2">
<div class="d-flex align-items-center gap-2 me-auto">
<input class="form-check-input m-0" type="checkbox" id="task_picker_add_focus" />
<label class="form-check-label mb-0" for="task_picker_add_focus">
Focused Task
</label>
</div>
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="offcanvas">
Cancel
</button>
<button type="button" class="btn btn-primary btn-sm" id="btn_task_picker_save" disabled>
<button type="button" class="btn btn-outline-success btn-sm" id="btn_task_picker_save" disabled>
Save
</button>
<button type="button" class="btn btn-primary btn-sm" id="btn_task_picker_select" disabled>
Select
</button>
</div>
</div>
</div>
......
......@@ -50,3 +50,17 @@
border-color: var(--bs-danger) !important;
padding-right: calc(1.5em + .75rem);
}
.time-row-saved > td {
animation: time-row-saved-flash 900ms ease-out;
}
@keyframes time-row-saved-flash {
from {
box-shadow: inset 0 0 0 999px rgba(25, 135, 84, 0.25);
}
to {
box-shadow: inset 0 0 0 999px rgba(25, 135, 84, 0);
}
}
\ No newline at end of file
......@@ -94,15 +94,15 @@
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.3.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.8.0;Comments=;LastCompiledTime=2018/08/27 15:18:29</VerInfo_Keys>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.4.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.8.0;Comments=;LastCompiledTime=2018/08/27 15:18:29</VerInfo_Keys>
<AppDPIAwarenessMode>PerMonitor</AppDPIAwarenessMode>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_Release>4</VerInfo_Release>
<TMSWebBrowser>1</TMSWebBrowser>
<TMSUseJSDebugger>2</TMSUseJSDebugger>
<VerInfo_Release>3</VerInfo_Release>
<TMSWebOutputPath>..\emT3XDataServer\bin\static</TMSWebOutputPath>
<TMSWebSingleInstance>1</TMSWebSingleInstance>
<TMSWebOutputPath>..\emT3XDataServer\bin\static</TMSWebOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
......
......@@ -7,10 +7,10 @@ object ApiDatabase: TApiDatabase
ProviderName = 'MySQL'
Database = 'eTask'
Username = 'root'
Server = '192.168.102.133'
Server = '192.168.90.131'
LoginPrompt = False
Left = 435
Top = 359
Left = 439
Top = 363
EncryptedPassword = '9AFF92FF8CFF86FF8CFFCFFFCEFF'
end
object MySQLUniProvider1: TMySQLUniProvider
......@@ -265,6 +265,60 @@ object ApiDatabase: TApiDatabase
Value = nil
end>
end
object uqCopyTaskItem: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'insert into task_items ('
' TASK_ID,'
' ITEM_NUM,'
' APPLICATION,'
' APP_VERSION,'
' TASK_DATE,'
' STATUS_DATE,'
' REPORTED_BY,'
' ASSIGNED_TO,'
' STATUS,'
' FIXED_VERSION,'
' FORM_SECTION,'
' ISSUE,'
' NOTES'
')'
'select'
' TASK_ID,'
' :ITEM_NUM,'
' APPLICATION,'
' APP_VERSION,'
' TASK_DATE,'
' STATUS_DATE,'
' REPORTED_BY,'
' ASSIGNED_TO,'
' STATUS,'
' FIXED_VERSION,'
' FORM_SECTION,'
' ISSUE,'
' NOTES'
'from task_items'
'where TASK_ID = :TASK_ID'
' and TASK_ITEM_ID = :TASK_ITEM_ID')
Left = 708
Top = 302
ParamData = <
item
DataType = ftInteger
Name = 'ITEM_NUM'
Value = nil
end
item
DataType = ftString
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftInteger
Name = 'TASK_ITEM_ID'
Value = nil
end>
end
object uqTaskHeader: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
......@@ -565,7 +619,8 @@ object ApiDatabase: TApiDatabase
'update task_items'
'set ITEM_NUM = ITEM_NUM + 1'
'where TASK_ID = :TASK_ID'
' and ITEM_NUM > :INSERT_AFTER_ITEM_NUM')
' and ITEM_NUM > :INSERT_AFTER_ITEM_NUM'
'order by ITEM_NUM desc')
Left = 538
Top = 76
ParamData = <
......@@ -798,7 +853,7 @@ object ApiDatabase: TApiDatabase
'where target_task.TASK_ID = :TASK_ID'
'order by tia.NAME')
Left = 58
Top = 314
Top = 316
ParamData = <
item
DataType = ftUnknown
......@@ -1224,50 +1279,47 @@ object ApiDatabase: TApiDatabase
SQL.Strings = (
'select distinct'
' c.CUSTOMER_ID,'
' c.SHORT_NAME as CUSTOMER_SHORT_NAME'
'from user_project up'
'join project p on p.PROJECT_ID = up.PROJECT_ID'
'join customers c on c.CUSTOMER_ID = p.CUSTOMER_ID'
'where up.USER_ID = :USER_ID'
'order by c.SHORT_NAME')
Left = 402
' c.NAME as CUSTOMER_NAME'
'from customers c '
'join project p on p.CUSTOMER_ID = c.CUSTOMER_ID'
'where p.STATUS = '#39'ACTIVE'#39
'order by c.NAME'
'')
Left = 404
Top = 494
ParamData = <
item
DataType = ftUnknown
Name = 'USER_ID'
Value = nil
end>
object uqTaskPickerCustomersCUSTOMER_ID: TStringField
FieldName = 'CUSTOMER_ID'
Size = 7
end
object uqTaskPickerCustomersCUSTOMER_SHORT_NAME: TStringField
FieldName = 'CUSTOMER_SHORT_NAME'
Size = 10
object uqTaskPickerCustomersCUSTOMER_NAME: TStringField
FieldName = 'CUSTOMER_NAME'
Size = 30
end
end
object uqTaskPickerProjects: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'select distinct'
'select'
' p.PROJECT_ID,'
' p.NAME as PROJECT_NAME'
'from user_project up'
'join project p on p.PROJECT_ID = up.PROJECT_ID'
'where up.USER_ID = :USER_ID'
' and p.CUSTOMER_ID = :CUSTOMER_ID'
'order by p.NAME')
' p.NAME as PROJECT_NAME,'
' p.CUSTOMER_ID'
'from project p '
'join customers c on c.CUSTOMER_ID = p.CUSTOMER_ID'
'where p.STATUS = '#39'ACTIVE'#39
'and (:CUSTOMER_ID = '#39#39' or p.CUSTOMER_ID = :CUSTOMER_ID)'
'order by p.NAME'
''
''
''
''
''
''
'')
Left = 544
Top = 494
ParamData = <
item
DataType = ftUnknown
Name = 'USER_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'CUSTOMER_ID'
Value = nil
end>
......@@ -1280,13 +1332,17 @@ object ApiDatabase: TApiDatabase
FieldName = 'PROJECT_NAME'
Size = 30
end
object uqTaskPickerProjectsCUSTOMER_ID: TStringField
FieldName = 'CUSTOMER_ID'
Size = 7
end
end
object uqTaskPickerTasks: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'select distinct'
' t.TASK_ID,'
' c.SHORT_NAME as CUSTOMER_SHORT_NAME,'
' c.SHORT_NAME as CUSTOMER_NAME,'
' p.NAME as PROJECT_NAME,'
' t.TASK_NUM_1,'
' t.TASK_NUM_2,'
......@@ -1298,9 +1354,8 @@ object ApiDatabase: TApiDatabase
'from tasks t'
'join project p on p.PROJECT_ID = t.PROJECT_ID'
'join customers c on c.CUSTOMER_ID = p.CUSTOMER_ID'
'join user_project up on up.PROJECT_ID = p.PROJECT_ID'
'where up.USER_ID = :USER_ID'
' and t.PROJECT_ID = :PROJECT_ID'
' where t.PROJECT_ID = :PROJECT_ID'
' and p.STATUS = '#39'ACTIVE'#39
'order by'
' t.TASK_NUM_1,'
' t.TASK_NUM_2,'
......@@ -1308,17 +1363,13 @@ object ApiDatabase: TApiDatabase
' t.TASK_NUM_4,'
' t.TASK_NUM_5,'
' t.TASK_NUM_6,'
' t.SUBJECT')
' t.SUBJECT'
'')
Left = 676
Top = 502
ParamData = <
item
DataType = ftUnknown
Name = 'USER_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'PROJECT_ID'
Value = nil
end>
......@@ -1327,10 +1378,10 @@ object ApiDatabase: TApiDatabase
Required = True
Size = 7
end
object uqTaskPickerTasksCUSTOMER_SHORT_NAME: TStringField
FieldName = 'CUSTOMER_SHORT_NAME'
object uqTaskPickerTasksCUSTOMER_NAME: TStringField
FieldName = 'CUSTOMER_NAME'
ReadOnly = True
Size = 10
Size = 30
end
object uqTaskPickerTasksPROJECT_NAME: TStringField
FieldName = 'PROJECT_NAME'
......
......@@ -19,6 +19,7 @@ type
uqSaveTaskRow: TUniQuery;
uqTaskItems: TUniQuery;
uqAddTaskRow: TUniQuery;
uqCopyTaskItem: TUniQuery;
uqTaskItemsTASK_ID: TStringField;
uqTaskItemsITEM_NUM: TShortintField;
uqTaskItemsAPPLICATION: TStringField;
......@@ -93,12 +94,11 @@ type
uqTaskPickerCustomers: TUniQuery;
uqTaskPickerProjects: TUniQuery;
uqTaskPickerTasks: TUniQuery;
uqTaskPickerCustomersCUSTOMER_ID: TStringField;
uqTaskPickerCustomersCUSTOMER_SHORT_NAME: TStringField;
uqTaskPickerProjectsPROJECT_ID: TStringField;
uqTaskPickerProjectsPROJECT_NAME: TStringField;
uqTaskPickerProjectsCUSTOMER_ID: TStringField;
uqTaskPickerTasksTASK_ID: TStringField;
uqTaskPickerTasksCUSTOMER_SHORT_NAME: TStringField;
uqTaskPickerTasksCUSTOMER_NAME: TStringField;
uqTaskPickerTasksPROJECT_NAME: TStringField;
uqTaskPickerTasksTASK_NUM_1: TIntegerField;
uqTaskPickerTasksTASK_NUM_2: TIntegerField;
......@@ -107,6 +107,8 @@ type
uqTaskPickerTasksTASK_NUM_5: TIntegerField;
uqTaskPickerTasksTASK_NUM_6: TIntegerField;
uqTaskPickerTasksTASK_SUBJECT: TStringField;
uqTaskPickerCustomersCUSTOMER_ID: TStringField;
uqTaskPickerCustomersCUSTOMER_NAME: TStringField;
procedure DataModuleCreate(Sender: TObject);
procedure uqUsersCalcFields(DataSet: TDataSet);
private
......
......@@ -120,6 +120,7 @@ type
[HttpGet] function GetTaskItems(taskId: string): TTaskItemsResponse;
[HttpPost] function AddTaskRow(taskId: string; insertAfterItemNum: Integer): Boolean;
[HttpPost] function CopyTaskRow(taskId: string; sourceTaskItemId: Integer): Integer;
[HttpPost] function AddAssignedName(taskId: string; name: string): TTaskUserOptionsResponse;
[HttpPost] function RenameAssignedName(taskId: string; oldName: string; newName: string): TTaskUserOptionsResponse;
......
......@@ -19,6 +19,7 @@ type
function FindAssignedOptionId(const taskId, name: string): string;
function FindAssignedOptionName(const taskId, name: string): string;
function AddTaskRow(taskId: string; insertAfterItemNum: Integer): Boolean;
function CopyTaskRow(taskId: string; sourceTaskItemId: Integer): Integer;
function BuildAssignedOptionsResponse(const taskId: string): TTaskUserOptionsResponse;
function AddAssignedName(taskId: string; name: string): TTaskUserOptionsResponse;
function RenameAssignedName(taskId: string; oldName: string; newName: string): TTaskUserOptionsResponse;
......@@ -50,6 +51,7 @@ implementation
procedure TTaskItemService.AfterConstruction;
begin
inherited;
Logger.Log(4, 'TaskItemService.AfterConstruction->TApiDatabase.Create(nil)');
apiDB := TApiDatabase.Create(nil);
Logger.Log(4, 'TaskItemService.AfterConstruction - apiDB created');
end;
......@@ -272,6 +274,66 @@ begin
end;
function TTaskItemService.CopyTaskRow(taskId: string; sourceTaskItemId: Integer): Integer;
var
q: TUniQuery;
sourceItemNum: Integer;
begin
Logger.Log(4, Format('TaskItemService.CopyTaskRow - TASK_ID="%s" SOURCE_TASK_ITEM_ID="%d"', [taskId, sourceTaskItemId]));
apiDB.uqGetTaskRowPosition.Close;
apiDB.uqGetTaskRowPosition.ParamByName('TASK_ID').AsString := taskId;
apiDB.uqGetTaskRowPosition.ParamByName('TASK_ITEM_ID').AsInteger := sourceTaskItemId;
apiDB.uqGetTaskRowPosition.Open;
if apiDB.uqGetTaskRowPosition.IsEmpty then
begin
Logger.Log(2, Format('TaskItemService.CopyTaskRow - row not found TASK_ID="%s" TASK_ITEM_ID="%d"', [taskId, sourceTaskItemId]));
raise Exception.Create('Task row not found.');
end;
sourceItemNum := apiDB.uqGetTaskRowPositionITEM_NUM.AsInteger;
q := TUniQuery.Create(nil);
try
q.Connection := apiDB.ucETaskApi;
apiDB.ucETaskApi.StartTransaction;
try
apiDB.uqShiftTaskRowsForInsert.Close;
apiDB.uqShiftTaskRowsForInsert.ParamByName('TASK_ID').AsString := taskId;
apiDB.uqShiftTaskRowsForInsert.ParamByName('INSERT_AFTER_ITEM_NUM').AsInteger := sourceItemNum;
apiDB.uqShiftTaskRowsForInsert.ExecSQL;
apiDB.uqCopyTaskItem.Close;
apiDB.uqCopyTaskItem.ParamByName('TASK_ID').AsString := taskId;
apiDB.uqCopyTaskItem.ParamByName('TASK_ITEM_ID').AsInteger := sourceTaskItemId;
apiDB.uqCopyTaskItem.ParamByName('ITEM_NUM').AsInteger := sourceItemNum + 1;
apiDB.uqCopyTaskItem.ExecSQL;
if apiDB.uqCopyTaskItem.RowsAffected <> 1 then
raise Exception.Create('Unable to copy the selected task row.');
q.SQL.Text := 'select LAST_INSERT_ID() as TASK_ITEM_ID';
q.Open;
Result := q.FieldByName('TASK_ITEM_ID').AsInteger;
apiDB.ucETaskApi.Commit;
Logger.Log(4, Format('TaskItemService.CopyTaskRow - OK TASK_ID="%s" SOURCE_TASK_ITEM_ID="%d" TASK_ITEM_ID="%d" ITEM_NUM="%d"',
[taskId, sourceTaskItemId, Result, sourceItemNum + 1]));
except
on E: Exception do
begin
if apiDB.ucETaskApi.InTransaction then
apiDB.ucETaskApi.Rollback;
Logger.Log(2, 'TaskItemService.CopyTaskRow - ERROR: ' + E.Message);
raise;
end;
end;
finally
q.Free;
end;
end;
procedure TTaskItemService.MoveTaskRow(const taskId: Integer; const taskItemId: Integer; const newItemNum: Integer);
var
oldItemNum: Integer;
......
......@@ -73,11 +73,11 @@ type
value: string;
end;
type
TTaskPickerOption = class
public
value: string;
display: string;
customerId: string;
end;
TTaskPickerOptionsResponse = class
......@@ -87,6 +87,13 @@ type
destructor Destroy; override;
end;
TTaskPickerTaskContext = class
public
taskId: string;
projectId: string;
customerId: string;
end;
[ServiceContract, Model(API_MODEL)]
ITimeEntryService = interface(IInvokable)
['{B18BCD1E-B19A-4D25-BBA9-50A24FC4C690}']
......@@ -95,9 +102,12 @@ type
[HttpPost] function SaveTimeEntry(Item: TTimeEntrySave): string;
[HttpPost] function SaveTimeEntryField(Item: TTimeEntryFieldSave): Boolean;
[HttpPost] function DeleteTimeEntry(userId: string; entryId: Integer): Boolean;
function GetTaskPickerCustomers(userId: string): TTaskPickerOptionsResponse;
function GetTaskPickerProjects(userId, customerId: string): TTaskPickerOptionsResponse;
function GetTaskPickerTasks(userId, projectId: string): TTaskPickerOptionsResponse;
[HttpPost] function AddTaskToFocus(userId, taskId: string): Boolean;
[HttpPost] function RemoveTaskFromFocus(userId, taskId: string): Boolean;
function GetTaskPickerCustomers: TTaskPickerOptionsResponse;
function GetTaskPickerProjects(customerId: string): TTaskPickerOptionsResponse;
function GetTaskPickerTasks(projectId: string): TTaskPickerOptionsResponse;
function GetTaskPickerTaskContext(taskId: string): TTaskPickerTaskContext;
end;
implementation
......
......@@ -34,10 +34,13 @@ type
function AddTimeEntry(userId, taskDate: string): string;
function SaveTimeEntry(Item: TTimeEntrySave): string;
function SaveTimeEntryField(Item: TTimeEntryFieldSave): Boolean;
function GetTaskPickerCustomers(userId: string): TTaskPickerOptionsResponse;
function GetTaskPickerProjects(userId, customerId: string): TTaskPickerOptionsResponse;
function GetTaskPickerTasks(userId, projectId: string): TTaskPickerOptionsResponse;
function GetTaskPickerCustomers: TTaskPickerOptionsResponse;
function GetTaskPickerProjects(customerId: string): TTaskPickerOptionsResponse;
function GetTaskPickerTasks(projectId: string): TTaskPickerOptionsResponse;
function GetTaskPickerTaskContext(taskId: string): TTaskPickerTaskContext;
function DeleteTimeEntry(userId: string; entryId: Integer): Boolean;
function AddTaskToFocus(userId, taskId: string): Boolean;
function RemoveTaskFromFocus(userId, taskId: string): Boolean;
end;
implementation
......@@ -50,7 +53,9 @@ uses
procedure TTimeEntryService.AfterConstruction;
begin
inherited;
Logger.Log(4, 'TTimeEntryService.AfterConstruction->TApiDatabase.Create(nil)');
apiDB := TApiDatabase.Create(nil);
Logger.Log(4, 'TTimeEntryService.AfterConstruction - apiDB created')
end;
......@@ -130,7 +135,7 @@ var
leftText: string;
taskText: string;
begin
customerText := FieldText(AQuery, 'CUSTOMER_SHORT_NAME');
customerText := FieldText(AQuery, 'CUSTOMER_NAME');
projectText := FieldText(AQuery, 'PROJECT_NAME');
taskNumberText := BuildTaskNumber(AQuery);
subjectText := FieldText(AQuery, 'TASK_SUBJECT');
......@@ -210,7 +215,7 @@ begin
' ti.CATEGORY, ' +
' cat.CODE_DESC as CATEGORY_DESC, ' +
' ti.SUMMARY, ' +
' c.SHORT_NAME as CUSTOMER_SHORT_NAME, ' +
' c.SHORT_NAME as CUSTOMER_NAME, ' +
' p.NAME as PROJECT_NAME, ' +
' t.TASK_NUM_1, ' +
' t.TASK_NUM_2, ' +
......@@ -290,7 +295,7 @@ begin
tasksQuery.SQL.Text :=
'select distinct ' +
' t.TASK_ID, ' +
' c.SHORT_NAME as CUSTOMER_SHORT_NAME, ' +
' c.SHORT_NAME as CUSTOMER_NAME, ' +
' p.NAME as PROJECT_NAME, ' +
' t.TASK_NUM_1, ' +
' t.TASK_NUM_2, ' +
......@@ -764,15 +769,14 @@ begin
end;
function TTimeEntryService.GetTaskPickerCustomers(userId: string): TTaskPickerOptionsResponse;
function TTimeEntryService.GetTaskPickerCustomers: TTaskPickerOptionsResponse;
begin
Logger.Log(4, Format('TimeEntryService.GetTaskPickerCustomers - USER_ID="%s"', [userId]));
Logger.Log(4, 'TimeEntryService.GetTaskPickerCustomers Start');
Result := TTaskPickerOptionsResponse.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
apiDB.uqTaskPickerCustomers.Close;
apiDB.uqTaskPickerCustomers.ParamByName('USER_ID').AsString := userId;
apiDB.uqTaskPickerCustomers.Open;
try
while not apiDB.uqTaskPickerCustomers.Eof do
......@@ -780,7 +784,7 @@ begin
AddTaskPickerOption(
Result,
FieldText(apiDB.uqTaskPickerCustomers, 'CUSTOMER_ID'),
FieldText(apiDB.uqTaskPickerCustomers, 'CUSTOMER_SHORT_NAME')
FieldText(apiDB.uqTaskPickerCustomers, 'CUSTOMER_NAME')
);
apiDB.uqTaskPickerCustomers.Next;
......@@ -791,15 +795,14 @@ begin
end;
function TTimeEntryService.GetTaskPickerProjects(userId, customerId: string): TTaskPickerOptionsResponse;
function TTimeEntryService.GetTaskPickerProjects(customerId: string): TTaskPickerOptionsResponse;
begin
Logger.Log(4, Format('TimeEntryService.GetTaskPickerProjects - USER_ID="%s" CUSTOMER_ID="%s"', [userId, customerId]));
Logger.Log(4, Format('TimeEntryService.GetTaskPickerProjects - CUSTOMER_ID="%s"', [customerId]));
Result := TTaskPickerOptionsResponse.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
apiDB.uqTaskPickerProjects.Close;
apiDB.uqTaskPickerProjects.ParamByName('USER_ID').AsString := userId;
apiDB.uqTaskPickerProjects.ParamByName('CUSTOMER_ID').AsString := customerId;
apiDB.uqTaskPickerProjects.Open;
try
......@@ -811,6 +814,9 @@ begin
FieldText(apiDB.uqTaskPickerProjects, 'PROJECT_NAME')
);
Result.options[Result.options.Count - 1].customerId :=
apiDB.uqTaskPickerProjectsCUSTOMER_ID.AsString;
apiDB.uqTaskPickerProjects.Next;
end;
finally
......@@ -819,15 +825,14 @@ begin
end;
function TTimeEntryService.GetTaskPickerTasks(userId, projectId: string): TTaskPickerOptionsResponse;
function TTimeEntryService.GetTaskPickerTasks(projectId: string): TTaskPickerOptionsResponse;
begin
Logger.Log(4, Format('TimeEntryService.GetTaskPickerTasks - USER_ID="%s" PROJECT_ID="%s"', [userId, projectId]));
Logger.Log(4, Format('TimeEntryService.GetTaskPickerTasks - PROJECT_ID="%s"', [projectId]));
Result := TTaskPickerOptionsResponse.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
apiDB.uqTaskPickerTasks.Close;
apiDB.uqTaskPickerTasks.ParamByName('USER_ID').AsString := userId;
apiDB.uqTaskPickerTasks.ParamByName('PROJECT_ID').AsString := projectId;
apiDB.uqTaskPickerTasks.Open;
try
......@@ -847,6 +852,39 @@ begin
end;
function TTimeEntryService.GetTaskPickerTaskContext(taskId: string): TTaskPickerTaskContext;
var
q: TUniQuery;
begin
Logger.Log(4, Format('TimeEntryService.GetTaskPickerTaskContext - TASK_ID="%s"', [taskId]));
Result := TTaskPickerTaskContext.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
Result.taskId := taskId;
// Read-only lookup; an unknown task returns blank ids so the picker opens empty
q := TUniQuery.Create(nil);
try
q.Connection := apiDB.ucETaskApi;
q.SQL.Text :=
'select t.PROJECT_ID, p.CUSTOMER_ID ' +
'from tasks t ' +
'join project p on p.PROJECT_ID = t.PROJECT_ID ' +
'where t.TASK_ID = :TASK_ID';
q.ParamByName('TASK_ID').AsString := taskId;
q.Open;
if not q.Eof then
begin
Result.projectId := FieldText(q, 'PROJECT_ID');
Result.customerId := FieldText(q, 'CUSTOMER_ID');
end;
finally
q.Free;
end;
end;
function TTimeEntryService.DeleteTimeEntry(userId: string; entryId: Integer): Boolean;
var
q: TUniQuery;
......@@ -890,6 +928,105 @@ begin
end;
end;
function TTimeEntryService.AddTaskToFocus(userId, taskId: string): Boolean;
var
q: TUniQuery;
begin
Logger.Log(4, Format(
'TimeEntryService.AddTaskToFocus - USER_ID="%s" TASK_ID="%s"',
[userId, taskId]
));
q := TUniQuery.Create(nil);
try
q.Connection := apiDB.ucETaskApi;
q.Connection.StartTransaction;
try
q.SQL.Text :=
'select TASK_ID from task_assigned_user ' +
'where USER_ID = :USER_ID and TASK_ID = :TASK_ID';
q.ParamByName('USER_ID').AsString := userId;
q.ParamByName('TASK_ID').AsString := taskId;
q.Open;
if q.IsEmpty then
begin
q.Close;
q.SQL.Text :=
'insert into task_assigned_user ' +
'(USER_ID, TASK_ID, FOCUSED_TASK) ' +
'values (:USER_ID, :TASK_ID, ''T'')';
end
else
begin
q.Close;
q.SQL.Text :=
'update task_assigned_user ' +
'set FOCUSED_TASK = ''T'' ' +
'where USER_ID = :USER_ID and TASK_ID = :TASK_ID';
end;
q.ParamByName('USER_ID').AsString := userId;
q.ParamByName('TASK_ID').AsString := taskId;
q.ExecSQL;
q.Connection.Commit;
Result := True;
except
on E: Exception do
begin
if q.Connection.InTransaction then
q.Connection.Rollback;
Logger.Log(2, 'TimeEntryService.AddTaskToFocus - ERROR: ' + E.Message);
raise;
end;
end;
finally
q.Free;
end;
end;
function TTimeEntryService.RemoveTaskFromFocus(userId, taskId: string): Boolean;
var
q: TUniQuery;
begin
Logger.Log(4, Format(
'TimeEntryService.RemoveTaskFromFocus - USER_ID="%s" TASK_ID="%s"',
[userId, taskId]
));
// Only clears the flag; the task_assigned_user row is kept and never inserted here
q := TUniQuery.Create(nil);
try
q.Connection := apiDB.ucETaskApi;
q.Connection.StartTransaction;
try
q.SQL.Text :=
'update task_assigned_user ' +
'set FOCUSED_TASK = ''F'' ' +
'where USER_ID = :USER_ID and TASK_ID = :TASK_ID';
q.ParamByName('USER_ID').AsString := userId;
q.ParamByName('TASK_ID').AsString := taskId;
q.ExecSQL;
q.Connection.Commit;
Result := True;
except
on E: Exception do
begin
if q.Connection.InTransaction then
q.Connection.Rollback;
Logger.Log(2, 'TimeEntryService.RemoveTaskFromFocus - ERROR: ' + E.Message);
raise;
end;
end;
finally
q.Free;
end;
end;
initialization
RegisterServiceType(TTimeEntryService);
......
[Settings]
MemoLogLevel=4
FileLogLevel=4
webClientVersion=0.9.3
LogFileNum=245
MemoLogLevel=5
FileLogLevel=5
webClientVersion=0.9.4.0
LogFileNum=218
[Database]
Server=192.168.102.133
--Server=192.168.116.131
--Server=192.168.102.131
--Server=192.168.116.128
--Server=192.168.102.131
--Server=192.168.159.10
Server=192.168.90.12
Database=eTask
Username=root
Password=emsys01
......
......@@ -114,12 +114,11 @@
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_ExeOutput>.\bin</DCC_ExeOutput>
<DCC_UnitSearchPath>C:\RADTOOLS\FastMM4;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<VerInfo_Keys>CompanyName=EM Systems;FileDescription=$(MSBuildProjectName);FileVersion=0.9.3.1;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.11;Comments=</VerInfo_Keys>
<VerInfo_Keys>CompanyName=EM Systems;FileDescription=$(MSBuildProjectName);FileVersion=0.9.4.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.11;Comments=</VerInfo_Keys>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_AutoIncVersion>true</VerInfo_AutoIncVersion>
<VerInfo_Build>1</VerInfo_Build>
<VerInfo_Release>3</VerInfo_Release>
<VerInfo_Release>4</VerInfo_Release>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment