// Add Customer page for KGOrders. Handles Adding and Editting Customers and
// Their shipping addresses.
unit View.Customer.Add;

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, WEBLib.Grids, VCL.Forms;

type
  TFViewAddCustomer = class(TWebForm)
    edtShortName: TWebDBEdit;
    edtName: TWebDBEdit;
    edtBillAddress: TWebDBEdit;
    edtBillCity: TWebDBEdit;
    edtBillState: TWebDBEdit;
    edtBillZip: TWebDBEdit;
    edtBillContact: TWebDBEdit;
    btnSave: TWebButton;
    btnCancel: TWebButton;
    btnDelete: TWebButton;
    btnClose: TWebButton;
    XDataWebClient1: TXDataWebClient;
    wdsCustomer: TWebDataSource;
    xdwdsCustomer: TXDataWebDataSet;
    xdwdsCustomerSHORT_NAME: TStringField;
    xdwdsCustomerNAME: TStringField;
    xdwdsCustomerBILL_ADDRESS: TStringField;
    xdwdsCustomerBILL_CITY: TStringField;
    edtCustomerID: TWebDBEdit;
    edtQBID: TWebDBEdit;
    wdsShipTo: TWebDataSource;
    xdwdsShipTo: TXDataWebDataSet;
    xdwdsCustomerBILL_STATE: TStringField;
    xdwdsCustomerBILL_CONTACT: TStringField;
    xdwdsCustomerBILL_ZIP: TStringField;
    xdwdsCustomerSTART_DATE: TStringField;
    xdwdsCustomerEND_DATE: TStringField;
    xdwdsCustomerQB_LIST_ID: TStringField;
    xdwdsCustomerFAX: TStringField;
    xdwdsCustomerPHONE: TStringField;
    xdwdsCustomerCUSTOMER_ID: TIntegerField;
    xdwdsShipToship_id: TStringField;
    xdwdsShipToshipping_address: TStringField;
    xdwdsShipTocity: TStringField;
    xdwdsShipTostate: TStringField;
    xdwdsShipTozip: TStringField;
    xdwdsShipTocontact: TStringField;
    memoAddressBlock: TWebMemo;
    btnAdd: TWebButton;
    btnShipSave: TWebButton;
    btnShipCancel: TWebButton;
    btnShipDelete: TWebButton;
    btnShipEdit: TWebButton;
    btnShipAdd: TWebButton;
    tmrReturn: TWebTimer;
    wdsUsers: TWebDataSource;
    xdwdsUsers: TXDataWebDataSet;
    lblFormState: TWebLabel;
    [async]
    btnLink: TWebButton;
    btnUpdate: TWebButton;
    edtRepUser: TWebDBEdit;
    xdwdsUsersQBID: TStringField;
    xdwdsCustomerQB_TYPE: TStringField;
    wdbtcAddresses: TWebDBTableControl;
    edtFirstLine: TWebDBEdit;
    xdwdsShipTofirst_line: TStringField;
    edtShippingState: TWebDBEdit;
    xdwdsShipToship_block: TMemoField;
    edtShippingAddress: TWebDBEdit;
    edtShippingCity: TWebDBEdit;
    edtShippingZip: TWebDBEdit;
    edtShippingContact: TWebDBEdit;
    memoShipBlock: TWebDBMemo; procedure btnSaveClick(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure btnEditClick(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure AddressEditMode();
    procedure edtShippingAddressChange(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure tmrReturnTimer(Sender: TObject);
    procedure btnDeleteClick(Sender: TObject);
    procedure btnShipAddClick(Sender: TObject);
    procedure btnShipEditClick(Sender: TObject);
    [async] procedure btnShipSaveClick(Sender: TObject);
    procedure btnShipDeleteClick(Sender: TObject);
    procedure btnShipCancelClick(Sender: TObject);
    procedure btnLinkClic(Sender: TObject);
    procedure btnUpdateClick(Sender: TObject);
    procedure wdblcbRepChange(Sender: TObject);
    procedure edtShortNameChange(Sender: TObject);
    procedure wdbtcAddressesClickCell(Sender: TObject; ACol, ARow: Integer);
    procedure edtCustomerIDChange(Sender: TObject);
  private
    { Private declarations }
    procedure ViewMode();
    procedure EditMode();
    [async] procedure GetCustomer();
    [async] procedure SendCustomerToServer();
    [async] procedure SendAddressToServer();
    [async] procedure DelAddress();
    [async] procedure Save();
    [async] procedure UpdateCustomer();
    function VerifyCustomer(): boolean;
    function VerifyAddress(): boolean;
    procedure Clear();
    procedure ShowSelectCustomerForm();
    [async] procedure InitializeForm;
  var
    customerID: string;
    QB_ID, qbCustJSON: string;
    mode: string;
    shipmode: string;
  public
    { Public declarations }
    class function CreateForm(AElementID, custID, custQB_ID: string): TWebForm;
  end;

var
  FViewAddCustomer: TFViewAddCustomer;

implementation

{$R *.dfm}

uses View.Main, View.Customers, View.Customer.Select, Utils;


class function TFViewAddCustomer.CreateForm(AElementID, custID, custQB_ID: string): TWebForm;
begin
  Application.CreateForm(TFViewAddCustomer, AElementID, Result,
    procedure(AForm: TObject)
    begin
      with TFViewAddCustomer(AForm) do
      begin
        customerID := custID;
        QB_ID := custQB_ID;

        InitializeForm;
      end;
    end
  );
end;


[async] procedure TFViewAddCustomer.InitializeForm;
var
  JSONObj, obj: TJSONObject;
  arr: TJSONArray;
  xdcResponse: TXDataClientResponse;
  RepUsers, QBCustomer: TJSObject;
  JSONStr: string;
  input: TJSHTMLInputElement;
begin
  if customerID = '' then
  begin
    mode := 'ADD';
    try
      try
        xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetQBCustomer', [QB_ID]));
        qbCustJSON := string(TJSJSON.stringify(xdcResponse.Result));
        JSONObj := TJSONObject.ParseJSONValue(qbCustJSON) as TJSONObject;
        //JSONObj := TJSONObject.ParseJSONValue(qbCustJSON) as TJSONObject;
        xdwdsCustomer.Open;
        xdwdsCustomer.Append;

        xdwdsCustomer.FieldByName('NAME').AsString := JSONObj.GetValue('NAME').Value;
        xdwdsCustomer.FieldByName('QB_LIST_ID').AsString := JSONObj.GetValue('QB_LIST_ID').Value;
        xdwdsCustomer.FieldByName('BILL_ADDRESS').AsString := JSONObj.GetValue('BILL_ADDRESS').Value;
        xdwdsCustomer.FieldByName('BILL_CITY').AsString := JSONObj.GetValue('BILL_CITY').Value;
        xdwdsCustomer.FieldByName('BILL_STATE').AsString := JSONObj.GetValue('BILL_STATE').Value;
        xdwdsCustomer.FieldByName('BILL_ZIP').AsString := JSONObj.GetValue('BILL_ZIP').Value;
        xdwdsCustomer.FieldByName('BILL_CONTACT').AsString := JSONObj.GetValue('BILL_CONTACT').Value;
        xdwdsCustomerQB_TYPE.AsString := JSONObj.GetValue('RepUser').Value;
        memoAddressBlock.Text := JSONObj.GetValue('BILL_ADDRESS_BLOCK').Value;



        //xdwdsCustomer.FieldByName('BILL_ADDRESS_BLOCK').AsString := JSONObj.GetValue('BILL_ADDRESS_BLOCK').Value;
        xdwdsCustomer.Post;

        xdwdsShipTo.Open;
        xdwdsShipTo.Append;
        xdwdsShipTo.FieldByName('shipping_address').AsString := JSONObj.GetValue('shipping_address').Value;
        xdwdsShipTo.FieldByName('city').AsString := JSONObj.GetValue('city').Value;
        xdwdsShipTo.FieldByName('state').AsString := JSONObj.GetValue('state').Value;
        xdwdsShipTo.FieldByName('zip').AsString := JSONObj.GetValue('zip').Value;
        xdwdsShipTo.FieldByName('ship_block').AsString := JSONObj.GetValue('ship_block').Value;
        xdwdsShipTo.FieldByName('contact').AsString := JSONObj.GetValue('contact').Value ;
        xdwdsShipTo.Post;
        xdwdsShipTo.First;

        xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetRepUsers', []));
        RepUsers :=  TJSObject(xdcResponse.Result);

        xdwdsUsers.Close;
        xdwdsUsers.SetJSONData(RepUsers['value']);
        xdwdsUsers.Open;
        CustomerID := '';

        input := TJSHTMLInputElement(document.getElementById('edtrepuser'));
        if not xdwdsUsers.Locate('QBID', xdwdsCustomerQB_TYPE.AsString, []) then
        begin
          input.classList.add('changed-field');
          input.classList.add('is-invalid');
        end
        else
          input.classList.remove('changed-field');

        EditMode();
      except
        on E: EXDataClientRequestException do
          Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
      end;
    finally
      JSONObj.Free;
    end;
  end
  else
  begin
    mode := 'EDIT';
    await(GetCustomer);
    ViewMode();
  end;
end;

procedure TFViewAddCustomer.Clear();
// Clears the shipping address fields.
begin
  edtShippingAddress.Text := '';
  edtShippingCity.Text := '';
  edtShippingState.Text := '';
  edtShippingZip.Text := '';
  edtShippingContact.Text := '';
  memoShipBlock.Text := '';
  edtFirstLine.Text := '';
end;

procedure TFViewAddCustomer.ShowSelectCustomerForm();
// displays the add order pop-up so the user can choose a customer
var
  newform: TFSelectCustomer;
begin
  newform := TFSelectCustomer.CreateNew;

  newform.Caption := 'Select Customer to Add';
  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
        FViewMain.ViewAddCustomer('', newform.QB_ID);
    end
  );
end;

procedure TFViewAddCustomer.DelAddress;
// Deletes a shipping address.
var
  Response: TXDataClientResponse;
  notification: TJSObject;
begin
  Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.DelShippingAddress',
              [xdwdsShipTo.FieldByName('ship_id').AsString, customerID]));
  notification := TJSObject(Response.Result);
  ShowToast(string(notification['status']));
  xdwdsShipTo.Close;
  xdwdsShipTo.SetJSONData(notification['ADDRESS']);
  xdwdsShipTo.Open;
  Utils.HideSpinner('spinner');
end;


procedure TFViewAddCustomer.SendAddressToServer;
// Creates an Address JSON and then sends it to the server for the address to be
// Added or edited.
var
  AddressJSON, JSONObj, test: TJSONObject;
  Response: TXDataClientResponse;
  notification, RowData, customer: TJSObject;
  address_list: TJSArray;
  ship_block: string;
  i: integer;
begin
  AddressJSON := TJSONObject.Create;

  AddressJSON.AddPair('address', edtShippingAddress.Text);
  AddressJSON.AddPair('city', edtShippingcity.Text);
  AddressJSON.AddPair('state', edtShippingstate.Text);
  AddressJSON.AddPair('zip', edtShippingzip.Text);
  AddressJSON.AddPair('contact', edtShippingContact.Text);
  AddressJSON.AddPair('customer_id', customerID);
  AddressJSON.AddPair('first_line', xdwdsShipTofirst_line.AsString);

  ship_block := edtFirstLine.Text + slinebreak +
                edtName.Text + slinebreak +
                edtShippingContact.Text + slinebreak +
                edtShippingAddress.Text + slinebreak +
                edtShippingCity.Text + ', ' + edtShippingState.Text + ' ' + edtShippingZip.Text;

  AddressJSON.AddPair('ship_block', ship_block);

  if shipmode = 'EDIT' then
    AddressJSON.AddPair('customer_ship_id', xdwdsShipTo.FieldByName('ship_id').AsString);

  AddressJSON.AddPair('mode', shipmode);
  xdwdsCustomer.Close;
  xdwdsShipTo.Close;
  Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.AddShippingAddress',
              [AddressJSON.ToString]));

  notification := TJSObject(Response.Result);

  ShowToast(string(notification['status']));

  customer := TJSObject(notification['customer']);
  xdwdsCustomer.Close;
  xdwdsCustomer.SetJsonData(customer);
  xdwdsCustomer.Open;


  edtCustomerID.Text := CustomerID;

  address_list := TJSArray(customer['SHIPPING_ADDRESS_LIST']);

  xdwdsShipTo.Close;
  xdwdsShipTo.Open;

  xdwdsShipTo.First;
  while not xdwdsShipTo.Eof do xdwdsShipTo.Delete;

  for i := 0 to address_list.length - 1 do
  begin
    RowData := TJSObject(address_list[i]);

    xdwdsShipTo.Append;
    xdwdsShipTo.FieldByName('state').AsString := String(RowData['state']);
    xdwdsShipTo.FieldByName('city').AsString  := String(RowData['city']);
    xdwdsShipTo.FieldByName('ship_id').AsString := String(RowData['ship_id']);
    xdwdsShipTo.FieldByName('shipping_address').AsString := String(RowData['shipping_address']);
    xdwdsShipTo.FieldByName('zip').AsString := String(RowData['zip']);
    xdwdsShipTo.FieldByName('ship_block').AsString := String(RowData['ship_block']);
    xdwdsShipTo.FieldByName('contact').AsString := String(RowData['contact']);
    xdwdsShipTo.FieldByName('first_line').AsString := String(RowData['first_line']);

    xdwdsShipTo.Post;
  end;
  xdwdsShipTo.First;

  memoAddressBlock.Text :=  string(customer['staff_fields_invoice_to']);
end;

procedure TFViewAddCustomer.btnAddClick(Sender: TObject);
// Takes the user to the Add Customer Page.
var
  AccessType: String;
begin
  AccessType := JS.toString(AuthService.TokenPayload.Properties['user_access_type']);
  if( ( AccessType =  'ADMIN' ) or ( AccessType = 'QBUSR' ) ) then
   ShowSelectCustomerForm()
  else
    ShowToast('Failure:User not authorized to add customer from QuickBooks', 'failure');
end;


procedure TFViewAddCustomer.btnCancelClick(Sender: TObject);
begin
  ShowConfirmationModal(
    'Are you sure you want to cancel all changes to the customer?',
    'Yes',
    'No',
    procedure(confirmed: Boolean)
    begin
      if confirmed then
      begin
        FViewMain.change := false;
        TJSHTMLInputElement(document.getElementById('edtcompanyname')).classList.remove('changed-field');
        TJSHTMLInputElement(document.getElementById('edtbillingaddress')).classList.remove('changed-field');
        TJSHTMLInputElement(document.getElementById('edtbillingcity')).classList.remove('changed-field');
        TJSHTMLInputElement(document.getElementById('edtbillingstate')).classList.remove('changed-field');
        TJSHTMLInputElement(document.getElementById('edtbillingzip')).classList.remove('changed-field');
        if CustomerID <> '' then
          FViewMain.ViewAddCustomer(CustomerID, 'Failure: Changes Discarded')
        else
          FViewMain.ShowForm(TFViewCustomers);
      end;
    end);
end;


procedure TFViewAddCustomer.btnClearClick(Sender: TObject);
// Clears the shipping address fields.
begin
  Clear();
end;


procedure TFViewAddCustomer.btnCloseClick(Sender: TObject);
// closes the Add Customer page.
begin
  FViewMain.ShowForm(TFViewCustomers)
end;


procedure TFViewAddCustomer.btnDeleteClick(Sender: TObject);
// Eventually will delete customers after a confirmation
// TODO implement deleting customers
begin
  ShowToast('Deleting Customers Is Not Yet Available', 'info');
  Exit;
end;

procedure TFViewAddCustomer.btnEditClick(Sender: TObject);
// Puts the form into edit mode
begin
  EditMode();
end;

procedure TFViewAddCustomer.btnLinkClic(Sender: TObject);
var
  newform: TFSelectCustomer;
  AccessType: string;
begin
  AccessType := JS.toString(AuthService.TokenPayload.Properties['user_access_type']);
  if( ( AccessType =  'ADMIN' ) or ( AccessType = 'QBUSR' ) ) then
  begin
    newform := TFSelectCustomer.CreateNew;

    newform.Caption := 'Select Customer to Link';
    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
          EditMode();
          xdwdsCustomer.Edit;
          xdwdsCustomerQB_LIST_ID.AsString := newform.QB_ID;
          xdwdsCustomer.Post;
          UpdateCustomer();
        end;
      end
    );
  end
  else
    ShowToast('Failure:User not authorized to link customer to QuickBooks', 'failure');

end;


procedure TFViewAddCustomer.edtCustomerIDChange(Sender: TObject);
begin
  EditMode();
end;

procedure TFViewAddCustomer.edtShippingAddressChange(Sender: TObject);
// Puts the form into Address Edit Mode
begin
  AddressEditMode();
end;


procedure TFViewAddCustomer.edtShortNameChange(Sender: TObject);
begin
  if lblFormState.Caption <> 'Edit Mode' then
    EditMode();
end;


procedure TFViewAddCustomer.wdblcbRepChange(Sender: TObject);
begin
  if lblFormState.Caption <> 'Edit Mode' then
    EditMode();
end;


procedure TFViewAddCustomer.wdbtcAddressesClickCell(Sender: TObject; ACol,
  ARow: Integer);
begin
  xdwdsShipTo.Locate('ship_id', wdbtcAddresses.Cells[0, ARow], []);

//  edtShippingAddress.Text := xdwdsShipTo.FieldByName('shipping_address').AsString;
//  edtShippingCity.Text := xdwdsShipTo.FieldByName('city').AsString;
//  edtShippingState.Text := xdwdsShipTo.FieldByName('state').AsString;
//  edtShippingZip.Text := xdwdsShipTo.FieldByName('zip').AsString;
//  edtShippingContact.Text := xdwdsShipTo.FieldByName('contact').AsString;
//  //memoShipBlock.Text := xdwdsShipTo.FieldByName('ship_block').AsString;

  if memoShipBlock.Lines.Count > 0 then
    edtFirstLine.Text := memoShipBlock.Lines[0]
  else
    edtFirstLine.Text := '';
end;


procedure TFViewAddCustomer.btnUpdateClick(Sender: TObject);
var
  AccessType: string;
begin
  if xdwdsCustomerQB_LIST_ID.AsString = '' then
    ShowToast('Failure:Company must be linked to quickbooks to update!')
  else
  begin
    AccessType := JS.toString(AuthService.TokenPayload.Properties['user_access_type']);
    if( ( AccessType =  'ADMIN' ) or ( AccessType = 'QBUSR' ) ) then
    begin
      UpdateCustomer();
    end
    else
      ShowToast('Failure:User not authorized to update customer from QuickBooks', 'failure');
  end;
end;


procedure TFViewAddCustomer.UpdateCustomer;
var
  customer: TJSObject;
  xdcResponse: TXDataClientResponse;
  msg, short_name: string;
  change: boolean;
  input: TJSHTMLInputElement;
begin
  try
    Utils.ShowSpinner('spinner');
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.UpdateCustomer', [xdwdsCustomerQB_LIST_ID.AsString]));
    customer :=  TJSObject(xdcResponse.Result);
    change := false;
    short_name := edtShortName.Text;

    input := TJSHTMLInputElement(document.getElementById('edtcompanyname'));
    if string(customer['NAME']) <> xdwdsCustomerNAME.AsString then
    begin
      input.classList.add('changed-field');
      change := true;
    end
    else
      input.classList.remove('changed-field');

    input := TJSHTMLInputElement(document.getElementById('edtbillingaddress'));
    if string(customer['BILL_ADDRESS']) <> xdwdsCustomerBILL_ADDRESS.AsString then
    begin
      input.classList.add('changed-field');
      change := true;
    end
    else
      input.classList.remove('changed-field');

    input := TJSHTMLInputElement(document.getElementById('edtbillingcity'));
    if string(customer['BILL_CITY']) <> xdwdsCustomerBILL_CITY.AsString then
    begin
      input.classList.add('changed-field');
      change := true;
    end
    else
      input.classList.remove('changed-field');

    input := TJSHTMLInputElement(document.getElementById('edtbillingstate'));
    if string(customer['BILL_STATE']) <> xdwdsCustomerBILL_STATE.AsString then
    begin
      input.classList.add('changed-field');
      change := true;
    end
    else
      input.classList.remove('changed-field');

    input := TJSHTMLInputElement(document.getElementById('edtbillingzip'));
    if string(customer['BILL_ZIP']) <> xdwdsCustomerBILL_ZIP.AsString then
    begin
      input.classList.add('changed-field');
      change := true;
    end
    else
      input.classList.remove('changed-field');

    input := TJSHTMLInputElement(document.getElementById('edtrepuser'));
    if string(customer['QB_TYPE']) <> xdwdsCustomerQB_TYPE.AsString then
    begin
      input.classList.add('changed-field');
      change := true;
    end
    else
      input.classList.remove('changed-field');

    if not xdwdsUsers.Locate('QBID', string(customer['QB_TYPE']), []) then
    begin
      input.classList.add('is-invalid');
    end
    else
      input.classList.remove('is-invalid');

    xdwdsCustomer.Close;
    xdwdsCustomer.SetJsonData(customer);
    xdwdsCustomer.Open;
    xdwdsCustomer.Edit;
    xdwdsCustomerCUSTOMER_ID.AsString := CustomerID;
    xdwdsCustomerSHORT_NAME.AsString := short_name;

;

    memoAddressBlock.Text :=  string(customer['staff_fields_invoice_to']);
    Utils.HideSpinner('spinner');
    if change then
    begin
      EditMode;
      ShowToast('Changes have been highlighted');
    end
    else
      ShowToast('No Changes needed');
  except
    on E: EXDataClientRequestException do
    begin
      Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
      ViewMode();
    end;
  end;
end;


procedure TFViewAddCustomer.SendCustomerToServer();
// Creates the customer JSON and then sends it to the server.
var
  customerJSON: TJSONObject;
  Field: TField;
  Response: TXDataClientResponse;
  notification: TJSObject;
  input: TJSHTMLElement;
  jsonObj: TJSONObject;
  msg: string;
  BILL_ADDRESS_BLOCK: string;
begin
  try
    if mode = 'EDIT' then
    begin
      customerJSON := TJSONObject.Create;
      xdwdsCustomer.First;

      while not xdwdsCustomer.Eof do
      begin
        for Field in xdwdsCustomer.Fields do
        begin
          if Field is TStringField then
          begin
            if Field.AsString = '' then
              customerJSON.AddPair(Field.FieldName, '')
            else
              customerJSON.AddPair(Field.FieldName, Field.AsString);  // Add all other fields
          end
          else if Field is TIntegerField then
          begin
            customerJSON.AddPair(Field.FieldName, Field.AsString);
          end;
        end;
        xdwdsCustomer.Next;
      end;

      BILL_ADDRESS_BLOCK := memoAddressBlock.Text;

      CustomerJSON.AddPair('BILL_ADDRESS_BLOCK', BILL_ADDRESS_BLOCK);

      customerJSON.AddPair('mode', mode);
      if mode = 'EDIT' then
        customerJSON.AddPair('CUSTOMER_ID', customerID);

      Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.AddCustomer',
        [customerJSON.ToJSON]));
      notification := TJSObject(Response.Result);
    end
    else
    begin
      JSONObj := TJSONObject.ParseJSONValue(qbCustJSON) as TJSONObject;
      JSONObj.AddPair('SHORT_NAME', xdwdsCustomerSHORT_NAME.AsString);
      Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.ImportQBCustomer',
                  [JSONObj.ToString]));
      notification := TJSObject(Response.Result);
    end;
    msg := string(notification['status']);

    ShowToast(msg);
    if msg.Contains('Failure') then
    begin
      input := TJSHTMLInputElement(document.getElementById('edtcompanyaccountname'));
      input.classList.add('is-invalid');
      input := TJSHTMLInputElement(document.getElementById('shortnamefeedback'));
      input.innerHTML := 'Customer ID must be unique.' ;
    end
    else
    begin
      if CustomerID = '' then
        CustomerID := string(notification['CustomerID']);
      xdwdsCustomer.Edit;
      edtCustomerID.Text := CustomerID;
      xdwdsCustomerCustomer_ID.AsInteger := integer(notification['CustomerID']);
      xdwdsCustomer.Post;
      TJSHTMLInputElement(document.getElementById('edtcompanyname')).classList.remove('changed-field');
      TJSHTMLInputElement(document.getElementById('edtbillingaddress')).classList.remove('changed-field');
      TJSHTMLInputElement(document.getElementById('edtbillingcity')).classList.remove('changed-field');
      TJSHTMLInputElement(document.getElementById('edtbillingstate')).classList.remove('changed-field');
      TJSHTMLInputElement(document.getElementById('edtbillingzip')).classList.remove('changed-field');
      mode := 'EDIT';
      await(GetCustomer());
      input := TJSHTMLInputElement(document.getElementById('edtrepuser'));
      input.classList.remove('changed-field');
      input.classList.remove('is-invalid');
      ViewMode();
    end;
  except
      on E: EXDataClientRequestException do
        Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
    end;
end;


procedure TFViewAddCustomer.btnSaveClick(Sender: TObject);
// Sends the customer JSON to the server
begin
  if VerifyCustomer() then
  begin
    Save();
  end;
end;


procedure TFViewAddCustomer.Save;
var
  input: TJSHTMLInputElement;
begin
  await(sendCustomerToServer());
end;


procedure TFViewAddCustomer.btnShipAddClick(Sender: TObject);
// Sets the form to address edit mode and allows the user to add a shipping address.
begin
  shipmode := 'ADD';
  Clear();
  AddressEditMode();
end;


procedure TFViewAddCustomer.btnShipCancelClick(Sender: TObject);
begin
  ShowConfirmationModal(
    'Are you sure you want to cancel address editing?',
    'Yes',
    'No',
    procedure(confirmed: Boolean)
    begin
      if confirmed then
      begin
        shipmode := '';
        Clear();
        ViewMode();
      end;
    end);
end;


procedure TFViewAddCustomer.btnShipDeleteClick(Sender: TObject);
begin
  ShowToast('Deleting shipping addresses is not yet implemented.', 'info');
  {ShowConfirmationModal(
    'Are you sure you want to delete this address?',
    'Delete',
    'Cancel',
    procedure(confirmed: Boolean)
    begin
      if confirmed then
      begin
        Utils.ShowSpinner('spinner');
        DelAddress();
        clear();
      end;
    end);   }
end;



procedure TFViewAddCustomer.btnShipEditClick(Sender: TObject);
// Sets the form into AddressEdit mode.
begin
  shipmode := 'EDIT';
  AddressEditMode();
end;

[async] procedure TFViewAddCustomer.btnShipSaveClick(Sender: TObject);
begin
  if (customerID = '') then
  begin
    ShowErrorModal('Cannot save address: Customer ID is not set.');
    Exit;
  end;

  if VerifyAddress() then
  begin
    await(SendAddressToServer);
    //Clear();
    //await(GetCustomer); // Ensures xdwdsShipTo is refreshed with server data
    ViewMode();
  end;
end;


procedure TFViewAddCustomer.GetCustomer;
// Retrieves a customer for a given CustomerID.
var
  xdcResponse: TXDataClientResponse;
  customer, RepUsers : TJSObject;
begin
  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetCustomer', [customerID]));
  customer :=  TJSObject(xdcResponse.Result);

  xdwdsCustomer.Close;
  xdwdsCustomer.SetJsonData(customer);
  xdwdsCustomer.Open;


  edtCustomerID.Text := CustomerID;

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

  memoAddressBlock.Text :=  string(customer['staff_fields_invoice_to']);
  edtShippingAddress.Text := xdwdsShipTo.FieldByName('shipping_address').AsString;
  edtShippingCity.Text := xdwdsShipTo.FieldByName('city').AsString;
  edtShippingState.Text := xdwdsShipTo.FieldByName('state').AsString;
  edtShippingZip.Text := xdwdsShipTo.FieldByName('zip').AsString;
  edtShippingContact.Text := xdwdsShipTo.FieldByName('contact').AsString;
  memoShipBlock.Text := xdwdsShipTo.FieldByName('ship_block').AsString;

  if memoShipBlock.Lines.Count > 0 then
    edtFirstLine.Text := memoShipBlock.Lines[0]
  else
    edtFirstLine.Text := '';

  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetRepUsers', []));
  RepUsers :=  TJSObject(xdcResponse.Result);

  xdwdsUsers.Close;
  xdwdsUsers.SetJSONData(RepUsers['value']);
  xdwdsUsers.Open;
end;


procedure TFViewAddCustomer.tmrReturnTimer(Sender: TObject);
// Timer to returnto the customer page  because it takes slightly too long to
// Delete customers causing ghost customers to show up.
begin
  Utils.HideSpinner('spinner');
  tmrReturn.Enabled := false;
  FViewMain.ViewCustomerList('Success:Customer Successfully Deleted');
end;

function TFViewAddCustomer.VerifyCustomer(): boolean;
var
  input: TJSHTMLElement;
begin
  result := true;

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

  input := TJSHTMLInputElement(document.getElementById('edtcompanyaccountname'));
  if edtShortName.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
    input := TJSHTMLInputElement(document.getElementById('shortnamefeedback'));
    input.innerHTML := 'Please Provide a Customer ID.' ;
  end
  else
    input.classList.remove('is-invalid');

  // Billing Information Verification
  input := TJSHTMLInputElement(document.getElementById('edtbillingaddress'));
  if edtBillAddress.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

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

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

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

end;


function TFViewAddCustomer.VerifyAddress: Boolean;
// Verifies all the shipping information is filled in.
var
  input: TJSHTMLElement;
begin
  result := true;
  input := TJSHTMLInputElement(document.getElementById('edtshippingaddress'));
  if edtShippingAddress.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

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

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

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

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

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

end;


procedure TFViewAddCustomer.EditMode;
// Enables Customer Fields while disabling shipping address fields.
begin
  xdwdsCustomer.Edit;
  FViewMain.change := true;
  btnAdd.Enabled := false;
  btnDelete.Enabled := false;
  btnClose.Enabled := false;
  btnSave.Enabled := true;
  btnCancel.Enabled := True;
  btnLink.Enabled := false;
  btnUpdate.Enabled := false;

  // Disable Shipping Address Editting
  edtShippingAddress.Enabled := false;
  edtShippingCity.Enabled := false;
  edtShippingState.Enabled := false;
  edtShippingZip.Enabled := false;
  edtShippingContact.Enabled := false;
  edtFirstLine.Enabled := false;

  btnShipDelete.Enabled := false;
  btnShipSave.Enabled := false;
  btnShipCancel.Enabled := false;
  btnShipEdit.Enabled := false;
  btnShipAdd.Enabled := false;

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


procedure TFViewAddCustomer.AddressEditMode;
// Enables Shipping Address fields while disabling customer fields.
begin
  xdwdsShipTo.Edit;
  FViewMain.change := true;
  btnDelete.Enabled := false;
  btnClose.Enabled := false;
  btnSave.Enabled := false;
  btnCancel.Enabled := false;
  btnAdd.Enabled := false;
  btnLink.Enabled := false;
  btnUpdate.Enabled := false;

  btnShipDelete.Enabled := false;
  btnShipSave.Enabled := true;
  btnShipCancel.Enabled := true;
  btnShipEdit.Enabled := false;
  btnShipAdd.Enabled := false;

  edtShippingAddress.Enabled := true;
  edtShippingCity.Enabled := true;
  edtShippingState.Enabled := true;
  edtShippingZip.Enabled := true;
  edtShippingContact.Enabled := true;
  edtFirstLine.Enabled := true;

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


procedure TFViewAddCustomer.ViewMode;
// Enables Customer Fields while disabling shipping address fields.
begin
  btnAdd.Enabled := true;
  btnDelete.Enabled := true;
  btnClose.Enabled := true;
  btnSave.Enabled := false;
  btnCancel.Enabled := false;
  btnLink.Enabled := true;
  btnUpdate.Enabled := true;
  FViewMain.change := false;

  btnShipAdd.Enabled := true;

  if not xdwdsShipTo.IsEmpty then
  begin
    btnShipDelete.Enabled := true;
    btnShipEdit.Enabled := true;
  end
  else
  begin
    btnShipDelete.Enabled := false;
    btnShipEdit.Enabled := false;
  end;

  btnShipSave.Enabled := false;
  btnShipCancel.Enabled := false;

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


end.