unit View.OrderEntryCuttingDie;

interface

uses
  System.SysUtils, System.Generics.Collections, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
  WEBLib.Forms, WEBLib.Dialogs, WEBLib.Menus, WEBLib.ExtCtrls, WEBLib.StdCtrls,
  WEBLib.JSON, Auth.Service, XData.Web.Client, WebLib.Storage,
  ConnectionModule, App.Types, Vcl.StdCtrls, Vcl.Controls, WEBLib.DBCtrls,
  Data.DB, XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, VCL.Forms;

type
  TFOrderEntryCuttingDie = class(TWebForm)
    wdsOrder: TWebDataSource;
    xdwdsOrder: TXDataWebDataSet;
    xdwdsOrderORDER_DATE: TDateField;
    xdwdsOrderSHORT_NAME: TStringField;
    xdwdsOrderstaff_fields_ship_via: TStringField;
    xdwdsOrderstaff_fields_price: TStringField;
    xdwdsOrderstaff_fields_invoice_to: TStringField;
    xdwdsOrderstaff_fields_invoice_attention: TStringField;
    xdwdsOrderstaff_fields_ship_to: TStringField;
    xdwdsOrderstaff_fields_ship_attention: TStringField;
    xdwdsOrderstaff_fields_po_number: TStringField;
    xdwdsOrderstaff_fields_job_name: TStringField;
    xdwdsOrderstaff_fields_order_date: TStringField;
    xdwdsOrderstaff_fields_proof_date: TStringField;
    xdwdsOrderstaff_fields_ship_date: TStringField;
    XDataWebClient1: TXDataWebClient;
    WebLabel2: TWebLabel;
    edtCompanyAccountName: TWebDBEdit;
    edtQBOrderNum: TWebDBEdit;
    WebLabel1: TWebLabel;
    dtpOrderDate: TWebDateTimePicker;
    dtpProofDate: TWebDateTimePicker;
    dtpShipDate: TWebDateTimePicker;
    edtShipVia: TWebDBEdit;
    edtQuantity: TWebDBEdit;
    edtPrice: TWebDBEdit;
    edtInvoiceTo: TWebDBEdit;
    wdbcbShipTo: TWebDBComboBox;
    edtPONumber: TWebDBEdit;
    edtJobName: TWebDBEdit;
    wdsShipTo: TWebDataSource;
    xdwdsShipTo: TXDataWebDataSet;
    xdwdsShipToADDRESS: TStringField;
    WebLabel9: TWebLabel;
    edtSpecialInstructions: TWebDBEdit;
    btnSave: TWebButton;
    btnCancel: TWebButton;
    edtCompanyName: TWebDBEdit;
    xdwdsOrderNAME: TStringField;
    xdwdsOrderstaff_fields_quickbooks_item: TStringField;
    xdwdsOrdergeneral_special_instructions: TStringField;
    xdwdsOrderstaff_fields_quantity: TStringField;
    wdsQBItem: TWebDataSource;
    xdwdsQBItem: TXDataWebDataSet;
    xdwdsQBItemname: TStringField;
    wcbQBItem: TWebDBComboBox;
    btnPDF: TWebButton;
    btnDelete: TWebButton;
    btnClose: TWebButton;
    btnCopy: TWebButton;
    tmrReturn: TWebTimer;
    btnEdit: TWebButton;
    btnAdd: TWebButton;
    WebButton2: TWebButton;
    lblFormState: TWebLabel;
    wdbcbINQB: TWebDBCheckBox;
    xdwdsOrderQB_ESTIMATE_ID: TStringField;
    xdwdsOrderQB_ORDER_NUM: TStringField;
    xdwdsOrderUSER_ID: TIntegerField;
    xdwdsOrderCOMPANY_ID: TIntegerField;
    xdwdsOrderORDER_ID: TIntegerField;
    edtOrderNum: TWebDBEdit;
    xdwdsOrderIN_QB: TStringField;
    WebButton1: TWebButton;
    procedure btnSaveClick(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);
    procedure WebFormCreate(Sender: TObject);
    [async] procedure GetCuttingDieOrder(Order_ID: string);
    [async] procedure GetCustomer(customerID: string);
    [async] procedure AddCuttingDieOrder(orderJSON: TJSONObject);
    procedure btnPDFClick(Sender: TObject);
    [async] procedure GenerateReportPDF;
    procedure SendOrderToServer();
    function VerifyOrder(): boolean;
    [async] procedure btnDeleteClick(Sender: TObject);
    [async] procedure delOrder();
    procedure btnCloseClick(Sender: TObject);
    procedure btnCopyClick(Sender: TObject);
    procedure tmrReturnTimer(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure btnEditClick(Sender: TObject);
    procedure ViewMode();
    procedure WebButton2Click(Sender: TObject);
    procedure ShowAddAddressForm();
    [async] procedure SendAddressToServer(AddressJSON: TJSONObject);
    procedure WebButton1Click(Sender: TObject);
  private
    FAgencyCode: string;
    FCurrentReportType: string;
    FSelectProc: TSelectProc;
    orderID: string;
    customerID: string;
    mode: string;
    notification: string;
    procedure EditMode;
    [async] procedure InitializeForm;
  public
    class function CreateForm(AElementID, orderInfo, customerInfo, modeParam, info: string): TWebForm;
  end;

var
  FOrderEntryCuttingDie: TFOrderEntryCuttingDie;

implementation

{$R *.dfm}

uses
  View.Home, View.Main, View.AddOrder, View.AddAddress, Utils;


class function TFOrderEntryCuttingDie.CreateForm(AElementID, orderInfo, customerInfo, modeParam, info: string): TWebForm;
begin
  Application.CreateForm(TFOrderEntryCuttingDie, AElementID, Result,
    procedure(AForm: TObject)
    begin
      with TFOrderEntryCuttingDie(AForm) do
      begin
        customerID := customerInfo;
        orderID := orderInfo;
        mode := modeParam;
        notification := info;

        InitializeForm;
      end;
    end
  );
end;


[async] procedure TFOrderEntryCuttingDie.InitializeForm;
begin
  if mode = 'ADD' then
  begin
    await(getCustomer(customerID));
    EditMode;
  end
  else
  begin
    await(getCuttingDieOrder(orderID));
    ViewMode;
  end;

  if notification <> '' then
    ShowToast(notification);
end;


procedure TFOrderEntryCuttingDie.WebButton1Click(Sender: TObject);
begin
  ShowToast('Sending Orders To QuickBooks is not yet Implemented', 'info');
end;

procedure TFOrderEntryCuttingDie.WebButton2Click(Sender: TObject);
begin
  ShowAddAddressForm();
end;


procedure TFOrderEntryCuttingDie.SendAddressToServer(AddressJSON: TJSONObject);
var
  Response: TXDataClientResponse;
  notification: TJSObject;
begin
  Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.AddShippingAddress',
              [AddressJSON.ToString]));

  notification := TJSObject(Response.Result);
  ShowToast(string(notification['status']));
  xdwdsShipTo.Close;
  xdwdsShipTo.SetJSONData(notification['ADDRESS']);
  xdwdsShipTo.Open;
end;


procedure TFOrderEntryCuttingDie.ShowAddAddressForm;
// displays the search pop-up that allows the user to filter the order list
var
  newform: TFViewAddAddress;
  AddressJSON: TJSONObject;
  ship_block: string;
begin
  newform := TFViewAddAddress.CreateNew;

  newform.Caption := 'Shipping Information';
  newForm.Popup := True;
  newForm.Border := fbDialog;
  newForm.Position := poScreenCenter;

  // used to manage Back button handling to close subform
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    var
      searchOptions: string;
    begin
      if newform.confirm then
      begin
        AddressJSON := TJSONObject.Create;

        AddressJSON.AddPair('address', newform.edtAddress.Text);
        AddressJSON.AddPair('city', newform.edtCity.Text);
        AddressJSON.AddPair('state', newform.edtState.Text);
        AddressJSON.AddPair('zip', newform.edtZip.Text);
        AddressJSON.AddPair('contact', newform.edtContact.Text);
        AddressJSON.AddPair('customer_id', xdwdsOrder.FieldByName('COMPANY_ID').AsString);

        ship_block := newform.edtFirstLine.Text + slinebreak +
                      edtCompanyName.Text + slinebreak +
                      newform.edtContact.Text + slinebreak +
                      newform.edtAddress.Text + slinebreak +
                      newform.edtCity.Text + ', ' + newform.edtState.Text + ' ' + newform.edtZip.Text;
        AddressJSON.AddPair('ship_block', ship_block);

        AddressJSON.AddPair('mode', 'ADD');
        sendAddressToServer(AddressJSON);
      end;
    end
  );
end;


function TFOrderEntryCuttingDie.VerifyOrder: Boolean;
var
  input: TJSHTMLInputElement;
begin
  result := true;

  input := TJSHTMLInputElement(document.getElementById('edtcompanyname'));
  if edtCompanyName.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');


  input := TJSHTMLInputElement(document.getElementById('edtaccountcompanyname'));
  if edtCompanyAccountName.Text = '' then
  begin

    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtinvoiceto'));
  if edtInvoiceTo.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');


  input := TJSHTMLInputElement(document.getElementById('wcbshipto'));
  if wdbcbShipTo.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('dtporderdate'));
  if dtpOrderDate.Date = 0 then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');
end;


procedure TFOrderEntryCuttingDie.SendOrderToServer;
var
  orderJSON: TJSONObject;
  fieldNames: TStringList;
  itemList: TJSNodeList;
  header, value: string;
  Field: TField;
  Response: TXDataClientResponse;
begin
  orderJSON := TJSONObject.Create;
  xdwdsOrder.Edit;

  //Convert all dates to strings because I was having less issues with that data type.
  xdwdsOrderstaff_fields_proof_date.Value := DateTimeToStr(dtpProofDate.Date);
  xdwdsOrderstaff_fields_ship_date.Value := DateTimeToStr(dtpShipDate.Date);
  xdwdsOrderstaff_fields_order_date.Value := DateTimeToStr(dtpOrderDate.Date);

  xdwdsOrder.Post;
  xdwdsOrder.First;
  while not xdwdsOrder.Eof do
  begin
    for Field in xdwdsOrder.Fields do
    begin
      if Field is TStringField then
      begin
        if Field.AsString = '' then
          orderJSON.AddPair(Field.FieldName, '')
        else
          orderJSON.AddPair(Field.FieldName, Field.AsString);  // Add all other fields
      end
      else if Field is TBooleanField then
      begin
        if Field.AsBoolean then
          orderJSON.AddPair(Field.FieldName, 'T')
        else
          orderJSON.AddPair(Field.FieldName, '');
      end
      else if Field is TIntegerField then
        orderJSON.AddPair(Field.FieldName, Field.AsInteger);
    end;
    xdwdsOrder.Next;
  end;

  console.log(orderJSON);

  orderJSON.AddPair('mode', mode);

  AddCuttingDieOrder(orderJSON);
end;


procedure TFOrderEntryCuttingDie.btnSaveClick(Sender: TObject);
// Converts all the information on the page into a JSON to then send to the server
begin
  if VerifyOrder() then
  begin
    sendOrderToServer();
    ViewMode();
  end;
  window.scrollTo(0, 0);
end;


procedure TFOrderEntryCuttingDie.btnCopyClick(Sender: TObject);
begin
  mode := 'ADD';
  dtpOrderDate.Date := 0;
  dtpProofDate.Date := 0;
  dtpShipDate.Date := 0;
  xdwdsOrder.Edit;
  xdwdsOrder.FieldByName('ORDER_ID').AsString := '';
  xdwdsOrder.Post;
  ShowToast('Success: Order Successfully Copied');
  EditMode();
  window.scrollTo(0, 0);
end;


[async] procedure TFOrderEntryCuttingDie.btnDeleteClick(Sender: TObject);
begin
  ShowConfirmationModal(
    'Are you sure you want to delete this order?',
    'Delete',
    'Cancel',
    procedure(confirmed: Boolean)
    begin
      if confirmed then
      begin
        Utils.ShowSpinner('spinner');
        DelOrder();
        tmrReturn.Enabled := true;
      end;
    end
  );
end;


procedure TFOrderEntryCuttingDie.btnEditClick(Sender: TObject);
begin
  EditMode;
end;


procedure TFOrderEntryCuttingDie.DelOrder();
var
  Response: TXDataClientResponse;
begin
  Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.DelOrder', [xdwdsOrder.FieldByName('ORDER_ID').AsString, 'cutting', JS.toString(AuthService.TokenPayload.Properties['user_id'])]));
end;


procedure TFOrderEntryCuttingDie.btnPDFClick(Sender: TObject);
begin
  GenerateReportPDF;
end;


[async] procedure TFOrderEntryCuttingDie.GenerateReportPDF;
// sends the search to the server which then sends back a pdf of the results
var
  xdcResponse: TXDataClientResponse;
  searchOptions, pdfURL: string;
  jsObject: TJSObject;
begin
  try
    // Call the server method to generate the PDF
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GenerateOrderCuttingPDF', [orderID]));
    jsObject := JS.TJSObject(xdcResponse.Result);
    pdfURL := JS.toString(jsObject.Properties['value']);

    // Open the PDF in a new browser tab without needing a different form
    // This method is much faster too, even for large datasets
    window.open(pdfURL, '_blank');
  except
    on E: EXDataClientRequestException do
      Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
  end;
end;


procedure TFOrderEntryCuttingDie.AddCuttingDieOrder(orderJSON: TJSONObject);
// sends the order JSON object to the server
var
  Response: TXDataClientResponse;
  jsObj: TJSObject;
begin
  try
    Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.AddCuttingDieOrder',
                [orderJSON.ToString]));
    jsObj := JS.TJSObject(Response.Result);
    {if mode = 'ADD' then
      OrderID := String(jsObj.Properties['OrderID']);}

    xdwdsOrder.Close;
    xdwdsOrder.SetJsonData(jsObj);
    xdwdsOrder.Open;

    edtOrderNum.Text := OrderID;
    mode := 'EDIT';
    ShowToast(String(jsObj.Properties['status']));
  except
    on E: EXDataClientRequestException do
      Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
  end;
end;


procedure TFOrderEntryCuttingDie.btnAddClick(Sender: TObject);
var
  newform: TFAddOrder;
  orderType: string;
begin
  newform := TFAddOrder.CreateNew;

  newform.Caption := 'Select Customer and Order Type';
  newForm.Popup := True;
  newForm.Border := fbDialog;
  newForm.Position := poScreenCenter;

  // used to manage Back button handling to close subform
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    begin
      if newform.confirm then
      begin
        if newform.cbCorrugatedPlate.Checked then
          orderType := 'corrugated'
        else if newform.cbWebPlate.Checked then
          orderType := 'web'
        else
          orderType := 'cutting';

        if orderType = 'corrugated' then
          FViewMain.ViewOrderEntryCorrugated('', newForm.DBID, 'ADD', '')
        else if orderType = 'web' then
          FViewMain.ViewOrderEntryWeb('', newForm.DBID, 'ADD', '')
        else
          FViewMain.ViewOrderEntryCuttingDie('', newForm.DBID, 'ADD', '');
      end;
    end
  );
end;


procedure TFOrderEntryCuttingDie.btnCancelClick(Sender: TObject);
begin
  ShowConfirmationModal(
    'Are you sure you want to cancel all changes?',
    'Yes',
    'No',
    procedure(confirmed: Boolean)
    begin
      if confirmed then
      begin
        FViewMain.change := false;
        if OrderID <> '' then
          FViewMain.ViewOrderEntryCuttingDie(OrderID, '', 'EDIT', 'Failure:  Changes Discarded')
        else
          FViewMain.ViewOrders('');
      end;
    end
  );
end;


procedure TFOrderEntryCuttingDie.btnCloseClick(Sender: TObject);
begin
  FViewMain.ViewOrders('');
end;

procedure TFOrderEntryCuttingDie.WebFormCreate(Sender: TObject);
begin
  if not DMConnection.ApiConnection.Connected then
    DMConnection.ApiConnection.OpenAsync;
end;


procedure TFOrderEntryCuttingDie.getCuttingDieOrder(Order_ID: string);
// retrieves an order from the server then loads the info into the page
var
  xdcResponse: TXDataClientResponse;
  orderList : TJSObject;
  i: integer;
  data: TJSArray;
  order, items: TJSObject;
begin
  Utils.ShowSpinner('spinner');
  try
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetCuttingDieOrder',
          [Order_ID]));
    order :=  TJSObject(xdcResponse.Result);
    data := TJSArray(order['data']);

    xdwdsOrder.Close;
    xdwdsOrder.SetJsonData(order);
    xdwdsOrder.Open;

    // Dates need to be manually set
    if not (xdwdsOrderstaff_fields_order_date.AsString = '') then
      dtpOrderDate.Date := StrToDateTime(xdwdsOrderstaff_fields_order_date.Value)
    else
      dtpOrderDate.Date := 0;
    if not (xdwdsOrderstaff_fields_proof_date.AsString = '') then
      dtpProofDate.Date := StrToDateTime(xdwdsOrderstaff_fields_proof_date.AsString)
    else
      dtpProofDate.Date := 0;
    if not (xdwdsOrderstaff_fields_ship_date.AsString = '') then
      dtpShipDate.Date := StrToDateTime(xdwdsOrderstaff_fields_ship_date.AsString)
    else
      dtpShipDate.Date := 0;

    xdwdsShipTo.Close;
    xdwdsShipTo.SetJSONData(order['ADDRESS_LIST']);
    xdwdsShipTo.Open;


    xdwdsQBItem.Close;
    items := TJSObject(order['ITEMS']);
    xdwdsQBItem.SetJsonData(items['data']);
    xdwdsQBITEM.Open;

  except
    on E: EXDataClientRequestException do
      Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
  end;
  Utils.HideSpinner('spinner');
end;


procedure TFOrderEntryCuttingDie.getCustomer(customerID: string);
// gets a customer from the database then loads the appropiate fields
var
  xdcResponse: TXDataClientResponse;
  customer : TJSObject;
  address: string;
  items: TJSObject;
begin

  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetCustomer',
        [customerID]));
  customer :=  TJSObject(xdcResponse.Result);
  xdwdsOrder.Close;
  xdwdsOrder.SetJsonData(customer);
  xdwdsOrder.Open;
  xdwdsOrder.Edit;
  xdwdsOrder.FieldByName('COMPANY_ID').AsString := customerID;

  xdwdsOrderUSER_ID.AsString := JS.toString(AuthService.TokenPayload.Properties['user_id']);
  xdwdsOrder.Post;

  dtpOrderDate.Date := 0;
  dtpProofDate.Date := 0;
  dtpShipDate.Date := 0;

  xdwdsShipTo.Close;
  xdwdsShipTo.SetJSONData(customer['ADDRESS_LIST']);
  xdwdsShipTo.Open;

  xdwdsQBItem.Close;
  items := TJSObject(customer['ITEMS']);
  xdwdsQBItem.SetJsonData(items['data']);
  xdwdsQBITEM.Open;
end;


procedure TFOrderEntryCuttingDie.tmrReturnTimer(Sender: TObject);
begin
  Utils.HideSpinner('spinner');
  tmrReturn.Enabled := false;
  FViewMain.ViewOrders('Success: Order Successfully Deleted');
end;


procedure TFOrderEntryCuttingDie.EditMode;
begin
  xdwdsOrder.Edit;
  FViewMain.change := true;
  btnCopy.Enabled := false;
  btnPDF.Enabled := false;
  btnDelete.Enabled := false;
  btnClose.Enabled := false;
  btnSave.Enabled := true;
  btnCancel.Enabled := True;
  btnEdit.Enabled := false;
  btnAdd.Enabled := false;

  lblFormState.Caption := 'Edit Mode';
  lblFormState.ElementHandle.classList.remove('text-danger');
  lblFormState.ElementHandle.classList.add('text-success');
end;


procedure TFOrderEntryCuttingDie.ViewMode;
begin
  btnPDF.Enabled := true;
  btnDelete.Enabled := true;
  btnClose.Enabled := true;
  btnCopy.Enabled := true;
  btnSave.Enabled := false;
  btnCancel.Enabled := false;
  btnEdit.Enabled := true;
  btnAdd.Enabled := true;
  FViewMain.change := false;

  lblFormState.Caption := 'View Mode';
  lblFormState.ElementHandle.classList.remove('text-success');
  lblFormState.ElementHandle.classList.add('text-danger');
end;


initialization
  RegisterClass(TFOrderEntryCuttingDie);

end.