namespace org.accordproject.latedeliveryandpenalty

import org.accordproject.runtime.*
import org.accordproject.time.*

// Declare a contract over a template model
contract LateDeliveryAndPenalty over TemplateModel {
  // Clause checking for late delivery and calculating penalty
  clause latedeliveryandpenalty(request : LateDeliveryAndPenaltyRequest) : LateDeliveryAndPenaltyResponse {
    // Guard against calling late delivery clause too early
    let agreed = request.agreedDelivery;
    enforce isBefore(agreed,now()) else
    throw Error{ message : "Cannot exercise late delivery before delivery date" }
    ;
    // Guard against force majeure
    enforce !contract.forceMajeure or !request.forceMajeure else
    return LateDeliveryAndPenaltyResponse{
      penalty: 0.0,
      buyerMayTerminate: true
    }
    ;

    // Calculate the time difference between current date and agreed upon date
    let diff = diffDurationAs(now(),agreed,~org.accordproject.time.TemporalUnit.days).amount;
    // Penalty formula
    let penalty =
      (integerToDouble(diff) / integerToDouble(contract.penaltyDuration.amount)) * contract.penaltyPercentage/100.0 * request.goodsValue;
    // Penalty may be capped
    let capped = min([penalty,contract.capPercentage * request.goodsValue / 100.0]);
    // Return the response with the penalty and termination determination
    return LateDeliveryAndPenaltyResponse{
      penalty: capped,
      buyerMayTerminate: diff > contract.termination.amount
    }
  }
}
