Source: products/argos-saleslogix/src/Integrations/BOE/Views/SalesOrders/Edit.js

import declare from 'dojo/_base/declare';
import lang from 'dojo/_base/lang';
import string from 'dojo/string';
import utility from 'argos/Utility';
import Edit from 'argos/Edit';
import Adapter from 'argos/Models/Adapter';
import validator from 'crm/Validator';
import MODEL_NAMES from '../../Models/Names';
import CRM_MODEL_NAMES from 'crm/Models/Names';
import BusyIndicator from 'argos/Dialogs/BusyIndicator';
import getResource from 'argos/I18n';
import Utility from '../../Utility';

const resource = getResource('salesOrderEdit');
const contactResource = getResource('contactModel');
const dtFormatResource = getResource('salesOrderEditDateTimeFormat');

/**
 * @class crm.Views.Account.Edit
 *
 * @extends argos.Edit
 *
 * @requires argos.Edit
 * @requires crm.Format
 * @requires crm.Validator
 * @requires crm.Template
 *
 */
const __class = declare('crm.Integrations.BOE.Views.SalesOrders.Edit', [Edit], {
  // View Properties
  id: 'salesorder_edit',
  detailView: 'salesorder_detail',
  insertSecurity: 'Entities/SalesOrder/Add',
  updateSecurity: 'Entities/SalesOrder/Edit',
  resourceKind: 'salesOrders',
  opportunityOpenCode: 'Open',
  warehouseCode: 'Warehouse',
  officeCode: 'Office',
  siteCode: 'Site',
  modelName: MODEL_NAMES.SALESORDER,
  _busyIndicator: null,

  // Localization
  titleText: resource.titleText,
  orderNumberText: resource.orderNumberText,
  orderIdText: resource.orderIdText,
  accountText: resource.accountText,
  opportunityText: resource.opportunityText,
  dateCreatedText: resource.dateCreatedText,
  erpStatusText: resource.erpStatusText,
  subTotalText: resource.subTotalText,
  grandTotalText: resource.grandTotalText,
  billToText: resource.billToText,
  shipToText: resource.shipToText,
  payFromText: resource.payFromText,
  dueDateText: resource.dueDateText,
  dateFormat: dtFormatResource.dateFormat,
  commentsText: resource.commentsText,
  productsText: resource.productsText,
  accountProducts: resource.accountProducts,
  requestedByText: resource.requestedByText,
  backOrderedText: resource.backOrderedText,
  taxExemptText: resource.taxExemptText,
  invoiceImmediatelyText: resource.invoiceImmediatelyText,
  dropShipmentText: resource.dropShipmentText,
  earlyShipmentText: resource.earlyShipmentText,
  partialShipText: resource.partialShipText,
  statusText: resource.statusText,
  statusTitle: resource.statusTitle,
  typeText: resource.typeText,
  typeTitle: resource.typeTitle,
  customerPOText: resource.customerPOText,
  currencyText: resource.currencyText,
  backOfficeText: resource.backOfficeText,
  accountingEntityText: resource.accountingEntityText,
  warehouseText: resource.warehouseText,
  warehouseLocationText: resource.warehouseLocationText,
  locationText: resource.locationText,
  locationsTitleText: resource.locationsTitleText,
  carrierText: resource.carrierText,

  init: function init() {
    this.inherited(arguments);

    this.connect(this.fields.Account, 'onChange', this.onAccountChange);
    this.connect(this.fields.RequestedBy, 'onChange', this.onContactChange);
    this.connect(this.fields.Opportunity, 'onChange', this.onOpportunityChange);
    this.connect(this.fields.BillTo, 'onChange', this.onBillToChange);
    this.connect(this.fields.ShipTo, 'onChange', this.onShipToChange);
    this.connect(this.fields.BackOffice, 'onChange', this.onBackOfficeChange);
    this.connect(this.fields.BackOfficeAccountingEntity, 'onChange', this.onBackOfficeAccountingEntityChange);
    this.connect(this.fields.Location, 'onChange', this.onLocationChange);
    this.connect(this.fields.Warehouse, 'onChange', this.onWarehouseChange);
  },
  processData: function processData() {
    this.showBusy();
    this.inherited(arguments);
    this.getEntriesFromIds();
  },
  beforeTransitionTo: function beforeTransitionTo() {
    this.inherited(arguments);
    if (!this.fields.AccountManager.isDisabled) {
      this.fields.AccountManager.disable();
    }
    if (this.fields.BillTo.isDisabled && this.fields.ShipTo.isDisabled) {
      this.fields.BillTo.enable();
      this.fields.ShipTo.enable();
    }
  },
  disableBackOfficeData: function disableBackOfficeData() {
    this.fields.BackOffice.disable();
    this.fields.BackOfficeAccountingEntity.disable();
  },
  enableBackOfficeData: function enableBackOfficeData() {
    this.fields.BackOffice.enable();
    this.fields.BackOfficeAccountingEntity.enable();
  },
  convertValues: function convertValues(values) {
    if (values.ErpBillTo) {
      values.ErpBillTo = {
        $key: values.ErpBillTo.$key,
      };
    }
    if (values.ErpShipTo) {
      values.ErpShipTo = {
        $key: values.ErpShipTo.$key,
      };
    }
    return values;
  },
  processEntry: function processEntry(entry) {
    if (entry && entry.Account) {
      ['RequestedBy', 'Opportunity'].forEach((f) => {
        this.fields[f].dependsOn = 'Account';
        this.fields[f].where = `Account.Id eq "${entry.Account.AccountId || entry.Account.$key || entry.Account.key}"`;
        if (f === 'Opportunity') {
          this.fields[f].where = `${this.fields[f].where} and Status eq "${this.opportunityOpenCode}"`;
        }
      });
    }
    const warehouseField = this.fields.Warehouse;
    const locationField = this.fields.Location;
    if (entry && entry.ErpLogicalId) {
      warehouseField.enable();
      warehouseField.dependsOn = 'ErpLogicalId';
      warehouseField.where = (logicalId) => {
        return `ErpLogicalId eq "${logicalId}" and LocationType eq "${this.warehouseCode}"`;
      };
      locationField.enable();
      locationField.dependsOn = 'ErpLogicalId';
      locationField.where = (logicalId) => {
        return `ErpLogicalId eq "${logicalId}" and (LocationType eq "${this.officeCode}" or LocationType eq "${this.siteCode}")`;
      };
    } else {
      warehouseField.disable();
      locationField.disable();
    }
    if (entry.WarehouseLocation) {
      warehouseField.setValue(entry.WarehouseLocation);
    }
    if (entry.Location) {
      locationField.setValue(entry.Location);
    }
    if (entry && entry.ErpExtId) {
      this.disableBackOfficeData();
    } else {
      this.enableBackOfficeData();
    }
    return entry;
  },
  setValues: function setValues() {
    this.inherited(arguments);

    if (!this.fields.CurrencyCode.getValue()) {
      const account = this.fields.Account.currentSelection;
      if (account && account.CurrencyCode) {
        this.fields.CurrencyCode.setValue(account.CurrencyCode);
      } else {
        this.fields.CurrencyCode.setValue(App.getBaseExchangeRate().code);
      }
    }
  },
  onRefresh: function onRefresh() {
    this.inherited(arguments);
    ['RequestedBy', 'Opportunity', 'Warehouse', 'Location'].forEach((f) => {
      this.fields[f].dependsOn = null;
      this.fields[f].where = null;
    });
  },
  onRefreshInsert: function onRefreshInsert() {
    this.inherited(arguments);
    this.enableBackOfficeData();
  },
  getEntriesFromIds: function getEntriesFromIds() {
    const mappedLookups = [
      'BackOffice',
      'BackOfficeAccountingEntity',
    ];
    const mappedProperties = [
      'LogicalId',
      'AcctEntityExtId',
    ];
    const fields = ['ErpLogicalId', 'ErpAccountingEntityId'];
    Utility.setFieldsFromIds(mappedLookups, mappedProperties, fields, this).then(() => {
      this.hideBusy();
    });
  },
  getPrimaryContact: function getPrimaryContact(entry) {
    const accountModel = Adapter.getModel(CRM_MODEL_NAMES.ACCOUNT);
    const relationship = {
      name: 'Contacts',
      displayName: contactResource.entityDisplayNamePlural,
      type: 'OneToMany',
      relatedEntity: 'Contact',
      relatedProperty: 'Account',
      relatedPropertyType: 'object',
      where: 'IsPrimary eq true',
    };
    accountModel.getRelatedRequest(entry, relationship).then((result) => {
      if (result && result.entities && result.entities.length) {
        const contactField = this.fields.RequestedBy;
        if (!contactField.currentSelection || contactField.currentSelection.Account && contactField.currentSelection.Account.$key !== entry.$key) {
          contactField.setSelection(result.entities[0]);
        }
      }
    });
  },
  onAccountChange: function onAccountChange(value, field) {
    const entry = field.currentSelection;
    ['RequestedBy', 'Opportunity'].forEach((f) => {
      if (value) {
        this.fields[f].dependsOn = 'Account';
        this.fields[f].where = `Account.Id eq "${value.AccountId || value.$key || value.key}"`;
      }
    });
    if (entry) {
      this.fields.CurrencyCode.setValue((entry.CurrencyCode) ? entry.CurrencyCode : App.getBaseExchangeRate().code);
      if (this.fields.BillTo.isDisabled && this.fields.ShipTo.isDisabled) {
        this.fields.BillTo.enable();
        this.fields.ShipTo.enable();
      }
      if (entry.AccountManager) {
        const accountManagerField = this.fields.AccountManager;
        accountManagerField.setSelection({
          $key: entry.AccountManager.$key,
        });
      }
      field.setValue(field.currentSelection);
      this.showBusy();
      this.getPrimaryContact(entry);
      Utility.setFieldsFromIds(
        ['BackOffice', 'BackOfficeAccountingEntity'],
        ['LogicalId', 'AcctEntityExtId'],
        ['ErpLogicalId', 'ErpAccountingEntityId'],
        this,
        entry
      ).then(() => {
        this.hideBusy();
      });
    }
  },
  onAccountDependentChange: function onAccountDependentChange(value, field) {
    if (value && !field.dependsOn && field.currentSelection && field.currentSelection.Account) {
      const accountField = this.fields.Account;
      accountField.setSelection(field.currentSelection.Account);
      this.onAccountChange(accountField.getValue(), accountField);
    }
  },
  onBackOfficeChange: function onBackOfficeChange(value, field) {
    this.fields.BackOffice.setValue(field.currentSelection);
    this.fields.ErpLogicalId.setValue(field.currentSelection.LogicalId);
    const accountingField = this.fields.BackOfficeAccountingEntity;
    accountingField.where = `BackOffice.Id eq "${field.currentSelection.$key}"`;
    const accountingIsToBackOffice = accountingField.currentSelection && accountingField.currentSelection.BackOffice.$key === field.currentSelection.$key;
    if (field.currentSelection.BackOfficeAccountingEntities.$resources && !accountingIsToBackOffice) {
      const entry = field.currentSelection.BackOfficeAccountingEntities.$resources[0];
      if (entry) {
        accountingField.setSelection(entry);
        this.onBackOfficeAccountingEntityChange(accountingField.getValue(), accountingField);
      }
    }
    const warehouseField = this.fields.Warehouse;
    if (warehouseField.isDisabled) {
      warehouseField.enable();
      warehouseField.dependsOn = 'ErpLogicalId';
      warehouseField.where = (logicalId) => {
        return `ErpLogicalId eq "${logicalId}" and LocationType eq "${this.warehouseCode}"`;
      };
    }
    const locationField = this.fields.Location;
    if (locationField.isDisabled) {
      locationField.enable();
      locationField.dependsOn = 'ErpLogicalId';
      locationField.where = (logicalId) => {
        return `ErpLogicalId eq "${logicalId}" and (LocationType eq "${this.officeCode}" or LocationType eq "${this.siteCode}")`;
      };
    }
  },
  onBackOfficeAccountingEntityChange: function onBackOfficeAccountingEntityChange(value, field) {
    this.fields.BackOfficeAccountingEntity.setValue(field.currentSelection);
    this.fields.ErpAccountingEntityId.setValue(field.currentSelection.AcctEntityExtId);
  },
  onBillToChange: function onBillToChange(value, field) {
    this.fields.BillTo.setValue(field.currentSelection);
  },
  onContactChange: function onContactChange(value, field) {
    this.onAccountDependentChange(value, field);
  },
  onLocationChange: function onLocationChance(value, field) {
    if (field.currentSelection.ErpExtId) {
      this.fields.ErpLocation.setValue(field.currentSelection.ErpExtId);
    }
    this.fields.Location.setValue(field.currentSelection);
  },
  onOpportunityChange: function onOpportunityChange(value, field) {
    this.onAccountDependentChange(value, field);
  },
  onShipToChange: function onShipToChange(value, field) {
    this.fields.ShipTo.setValue(field.currentSelection);
  },
  onWarehouseChange: function onWarehouseChange(value, field) {
    this.fields.Warehouse.setValue(field.currentSelection);
  },
  applyContext: function applyContext() {
    this.inherited(arguments);
    const found = this._getNavContext();

    const accountField = this.fields.Account;
    this.onAccountChange(accountField.getValue(), accountField);

    const context = (found && found.options && found.options.source) || found;
    const lookup = {
      accounts: this.applyAccountContext,
      contacts: this.applyContactContext,
      opportunities: this.applyOpportunityContext,
    };

    if (context && lookup[context.resourceKind]) {
      lookup[context.resourceKind].call(this, context);
    }

    if (!this.fields.Account.currentSelection && !this.fields.Account.currentValue) {
      this.fields.BillTo.disable();
      this.fields.ShipTo.disable();
    }
    if (!this.fields.BackOffice.currentSelection) {
      this.fields.Location.disable();
      this.fields.Warehouse.disable();
    }
  },
  _getNavContext: function _getNavContext() {
    const navContext = App.queryNavigationContext((o) => {
      const context = (o.options && o.options.source) || o;

      if (/^(accounts|contacts|opportunities)$/.test(context.resourceKind) && context.key) {
        return true;
      }

      return false;
    });
    return navContext;
  },
  applyAccountContext: function applyAccountContext(context) {
    const view = App.getView(context.id);
    const entry = context.entry || (view && view.entry) || context;

    if (!entry || !entry.$key) {
      return;
    }

    const accountField = this.fields.Account;
    accountField.setSelection(entry);
    this.onAccountChange(accountField.getValue(), accountField);
  },
  applyContactContext: function applyContactContext(context) {
    const view = App.getView(context.id);
    const entry = context.entry || (view && view.entry) || context;

    if (!entry || !entry.$key) {
      return;
    }

    const contactField = this.fields.RequestedBy;
    contactField.setSelection(entry);
    this.onAccountDependentChange(contactField.getValue(), contactField);
  },
  applyOpportunityContext: function applyOpportunityContext(context) {
    const view = App.getView(context.id);
    const entry = context.entry || (view && view.entry) || context;

    if (!entry || !entry.$key) {
      return;
    }

    const opportunityField = this.fields.Opportunity;
    opportunityField.setSelection(entry);
    this.onAccountDependentChange(opportunityField.getValue(), opportunityField);
  },
  hideBusy: function hideBusy() {
    if (this._busyIndicator) {
      this._busyIndicator.complete();
      App.modal.disableClose = false;
      App.modal.hide();
    }
  },
  showBusy: function showBusy() {
    if (!this._busyIndicator || this._busyIndicator._destroyed) {
      this._busyIndicator = new BusyIndicator({ id: `${this.id}-busyIndicator` });
    }
    this._busyIndicator.start();
    App.modal.disableClose = true;
    App.modal.showToolbar = false;
    App.modal.add(this._busyIndicator);
  },
  formatDependentQuery: function formatDependentQuery(dependentValue, theFormat, property) {
    return string.substitute(theFormat, [utility.getValue(dependentValue, property || '$key')]);
  },
  createLayout: function createLayout() {
    return this.layout || (this.layout = [{
      title: this.detailsText,
      name: 'DetailsSection',
      children: [{
        label: this.accountText,
        name: 'Account',
        property: 'Account',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'AccountName',
        view: 'account_related',
        autoFocus: true,
        required: true,
        validator: validator.exists,
      }, {
        label: this.opportunityText,
        name: 'Opportunity',
        property: 'Opportunity',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'Description',
        view: 'opportunity_related',
      }, {
        label: this.backOfficeText,
        name: 'BackOffice',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'BackOfficeName',
        view: 'salesorder_backoffice_related',
        where: 'IsActive eq true',
        include: false,
      }, {
        name: 'ErpLogicalId',
        property: 'ErpLogicalId',
        type: 'hidden',
        emptyText: '',
      }, {
        label: this.accountingEntityText,
        name: 'BackOfficeAccountingEntity',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'Name',
        view: 'salesorder_backofficeaccountingentity_related',
        include: false,
      }, {
        name: 'ErpAccountingEntityId',
        property: 'ErpAccountingEntityId',
        type: 'hidden',
        emptyText: '',
      }, {
        label: this.currencyText,
        name: 'CurrencyCode',
        property: 'CurrencyCode',
        type: 'picklist',
        picklist: 'Currency Codes',
        singleSelect: true,
        textProperty: 'code',
        keyProperty: 'code',
        required: true,
        requireSelection: true,
        validator: validator.picklistExists,
      }, {
        label: this.dueDateText,
        name: 'DueDate',
        property: 'DueDate',
        type: 'date',
        timeless: false,
        showTimePicker: true,
        showRelativeDateTime: false,
        dateFormatText: this.dateFormat,
        minValue: (new Date(1900, 0, 1)),
        validator: [
          validator.isDateInRange,
        ],
      }, {
        label: this.customerPOText,
        name: 'CustomerPONumber',
        property: 'CustomerPurchaseOrderNumber',
        type: 'text',
      }, {
        label: this.commentsText, // TODO: Make on save, append 'Created by <user> on <datetime>' to comment
        noteProperty: false,
        name: 'Comments',
        property: 'Comments',
        title: this.commentsText,
        type: 'note',
        view: 'text_edit',
      }, {
        label: this.locationText,
        name: 'Location',
        property: 'Location',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'Description',
        view: 'quote_location_list',
        title: this.locationsTitleText,
      }, {
        name: 'ErpLocation',
        property: 'ErpLocation',
        type: 'hidden',
        emptyText: '',
      }, {
        label: this.warehouseText,
        name: 'Warehouse',
        property: 'WarehouseLocation',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'Description',
        view: 'order_warehouse_list',
        title: this.warehouseLocationText,
      }, {
        label: this.requestedByText,
        name: 'RequestedBy',
        property: 'RequestedBy',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'NameLF',
        view: 'contact_related',
      }, {
        label: this.statusText,
        name: 'Sales Order Status',
        property: 'Status',
        type: 'picklist',
        picklist: 'Sales Order Status',
        singleSelect: true,
        titleText: this.statusTitle,
      }, {
        dependsOn: 'Account',
        label: this.billToText,
        name: 'BillTo',
        property: 'ErpBillTo',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'Address.FullAddress',
        view: 'salesorder_billTo_related',
        where: this.formatDependentQuery.bindDelegate(
          this, 'ErpBillToAccounts.Account.Id eq "${0}"'
        ),
      }, {
        dependsOn: 'Account',
        label: this.shipToText,
        name: 'ShipTo',
        property: 'ErpShipTo',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'Address.FullAddress',
        view: 'salesorder_shipTo_related',
        where: this.formatDependentQuery.bindDelegate(
          this, 'ErpShipToAccounts.Account.Id eq "${0}"'
        ),
      }, {
        dependsOn: 'ErpLogicalId',
        label: this.carrierText,
        name: 'Carrier',
        property: 'Carrier',
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'CarrierName',
        view: 'salesorder_carriers',
        where: (value) => {
          return `ErpLogicalId eq "${value}"`;
        },
      }, {
        label: this.backOrderedText,
        name: 'BackOrdered',
        property: 'ErpBackOrdered',
        include: true,
        type: 'boolean',
        onText: this.yesText,
        offText: this.noText,
      }, {
        label: this.dropShipmentText,
        name: 'DropShipment',
        property: 'ErpDropShip',
        include: true,
        type: 'boolean',
        onText: this.yesText,
        offText: this.noText,
      }, {
        label: this.earlyShipmentText,
        name: 'EarlyShipment',
        property: 'ErpShipEarly',
        include: true,
        type: 'boolean',
        onText: this.yesText,
        offText: this.noText,
      }, {
        label: this.invoiceImmediatelyText,
        name: 'InvoiceImmediately',
        property: 'ErpInvoiceImmediately',
        include: true,
        type: 'boolean',
        onText: this.yesText,
        offText: this.noText,
      }, {
        label: this.partialShipText,
        name: 'PartialShipment',
        property: 'ErpPartialShipAllowed',
        include: true,
        type: 'boolean',
        onText: this.yesText,
        offText: this.noText,
      }, {
        label: this.taxExemptText,
        name: 'TaxExempt',
        property: 'ErpTaxExempt',
        include: true,
        type: 'boolean',
        onText: this.yesText,
        offText: this.noText,
      }, {
        label: this.accountManagerText,
        name: 'AccountManager',
        property: 'AccountManager',
        include: true,
        type: 'lookup',
        emptyText: '',
        valueTextProperty: 'Name',
      },
      ] },
    ]);
  },
});

lang.setObject('icboe.Views.SalesOrders.Edit', __class);
export default __class;