// ==========================================================================
// Project:   xTuple Postbooks - Business Management System Framework        
// Copyright: ©2012 OpenMFG LLC, d/b/a xTuple                             
// ==========================================================================

/*globals XM */

/**
  @class
  
  Used to consolidate receivable and cash receipt detail into a single object.

  @extends SC.Object
*/
XM.CashReceiptApplication = SC.Object.extend(
  /** @scope XM.CashReceiptApplication.prototype */ {
  
  cashReceipt: null,
  
  cashReceiptDetail: null,
  
  receivable: null,

  // .................................................
  // CALCULATED PROPERTIES
  //
  
  /**
    The amount to be applied to the associated receivable.
    
    @type Number
  */
  applied: function() {
    return this.getPath('cashReceiptDetail.amount') || 0;
  }.property('*cashReceiptDetail.amount').cacheable(),

  /**
    The discount to be applied to the associated receivable.
    
    @type Number
  */
  discount: function() {
    return this.getPath('cashReceiptDetail.discount') || 0;
  }.property('*cashReceiptDetail.discount').cacheable(),
  
  /**
    Total applied amount of this cash receipt in the currency of the receivable.
    
    @type Number
  */
  receivableApplied: function() {
    var applied = this.get('applied'),
        discount = this.get('discount'),
        crCurrencyRate = this.getPath('cashReceipt.currencyRate') || 1,
        arCurrencyRate = this.getPath('receivable.currencyRate');
    return SC.Math.round((applied + discount) * arCurrencyRate / crCurrencyRate, XT.MONEY_SCALE);
  }.property('applied', 'discount').cacheable(),
  
  /**
    Total value of applications that have been created, but not posted, on the receivable
    in the receivable's currency.
    
    @type Number
  */
  allPending: function() {
    var applications = this.getPath('receivable.pendingApplications'),
        id = this.getPath('cashReceiptDetail.id') || -1,
        receivableApplied = this.get('receivableApplied'), 
        pending = 0;
  
    // loop through all pending applications and add them up
    for (var i = 0; i < applications.get('length'); i++) {
      var application = applications.objectAt(i),
          pendingApplicationType = application.get('pendingApplicationType'),
          amount = application.get('amount');
          
      // only include pending applications that are not the application from _this_ receipt
      if (pendingApplicationType !== XM.PendingApplication.CASH_RECEIPT || 
          application.get('id') !== id) {
        pending += amount;
      }
    }
    
    // now add the amount applied from this application
    pending += receivableApplied;
    return SC.Math.round(pending, XT.MONEY_SCALE);
  }.property('*receivable.pendingApplications.length', 'receivableApplied').cacheable(),

  /**
    The balance due on the receivable in the receivable's currency.
    
    @type Number
  */  
  balance: function() {
    var balance = this.getPath('receivable.balance'),
        allPending = this.get('allPending');
    return SC.Math.round(balance - allPending, XT.MONEY_SCALE);
  }.property('allPending').cacheable(),
  
  // .................................................
  // METHODS
  //
  
  /**
    Apply an amount from the cash receipt associated with this application
    to the receivable associtated with this application.
    
    @param {Number} amount
    @param {Number} discount
    returns XM.CashReceiptDetail
  */
  apply: function(amount, discount) {
    var cashReceipt = this.get('cashReceipt'),
        detail = this.get('cashReceiptDetail'),
        receivable = this.get('receivable'),
        applied = detail ? detail.get('amount') : 0,
        balance = receivable.get('balance'),
        store = receivable.get('store'),
        pending; 
    
    // values must be valid
    discount = discount || 0;
    if (amount < 0 || discount < 0 || 
        amount + discount - applied > balance) return false;
  
    // update the detail
    if (detail) {
      detail.set('amount', amount);
      detail.set('discount', discount);

    // create the detail
    } else {
      detail = store.createRecord(XM.CashReceiptDetail, {});
      detail.set('receivable', receivable)
            .set('amount', amount)
            .set('discount', discount);
      cashReceipt.get('details').pushObject(detail);
                
      // associate detail to this application
      this.set('cashReceiptDetail', detail);
      
      // fetching the id is asynchronous, so we'll have to finish when that comes
      detail.addObserver('id', detail, function observer() {
        if (!isNaN(detail.get('id'))) {
          detail.removeObserver('id', detail, observer);
          id = detail.get('id');
          
          // create a pending application record (info only, this won't be committed)
          pending = store.createRecord(XM.PendingApplication, { guid: id });
          pending.set('pendingApplicationType', XM.PendingApplication.CASH_RECEIPT)
                 .set('receivable', receivable)
                 .set('amount', amount + discount);
          
          // associate detail to pending applications
          receivable.get('pendingApplications').pushObject(pending);
        }
      })

      // get id
      detail.normalize();
    }
    return detail;
  },
  
  applyBalance: function() {
  },
  
  clear: function() {
    var detail = this.get('cashReceiptDetail');
    if (detail) detail.destroy();
    this.set('cashReceiptDetail', null);
  }
  
  // .................................................
  // OBSERVERS
  //
  
});


@@ -5422,16 +5422,1155 @@
 ion() %7B%0A
+    var applied = this.get('applied'),%0A        amount = this.getPath('cashReceipt.balance') + applied,%0A        receivable = this.get('receivable'),%0A        balance = receivable.get('balance') + applied,%0A        documentDate = receivable.get('documentDate'),%0A        terms = receivable.get('terms'),%0A        discountDate = terms.calculateDiscountDate(documentDate),%0A        discountPercent = terms.get('discountPercent') / 100,%0A        discount = 0;%0A        %0A    // bail out if nothing to do%0A    if (balance === 0 %7C%7C amount === 0) return this.get('detail');%0A    %0A    // calculate discount if we qualify for one%0A    if (balance %3E 0 && SC.DateTime.compareDate(documentDate, discountDate) %3C= 0) %7B%0A      discount = SC.Math.round(balance * discountPercent, XT.MONEY_SCALE);%0A    %7D%0A    %0A    // adjust the amount or discount as appropriate and apply%0A    if (balance %3C= amount + discount) %7B%0A      amount = balance - discount;%0A    %7D else %7B%0A      discount = SC.Math.round((amount / (1 - discountPercent)) - amount, XT.MONEY_SCALE);%0A    %7D%0A    if (amount) return this.apply(amount, discount);%0A    %0A    // if there was nothing to apply%0A    return false;%0A
   %7D,%0A  %0A

add apply line balance function.