. * * You can get complete code of ProjeQtOr, other resource, help and information * about contributors at http://www.projeqtor.org * * ** DO NOT REMOVE THIS NOTICE *********************************************** */ /** ============================================================================ * creation of the description of the content for a bill. */ require_once(__DIR__ . '/persistence/_securityCheck.php'); class BillMain extends SqlElement { const DEFAULT_RECIPIENT = 1; // List of fields that will be exposed in general user interface public $_sec_description; public $id; // redefine $id to specify its visible place public $reference; public $name; public $idBillType; public $idProject; public $idUser; public $creationDate; public $date; public $idPaymentDelay; public $paymentDueDate; public $idClient; public $idContact; public $idRecipient; public $Origin; public $_spe_billingType; public $_sec_treatment; public $billId; public $idStatus; public $idResource; public $sendDate; public $idDeliveryMode; public $done; public $idle; public $cancelled; public $_lib_cancelled; public $_tab_5_1_smallLabel = array('untaxedAmountShort', 'tax', '', 'fullAmountShort', 'commandAmountPctShort', 'amount'); public $untaxedAmount; public $taxPct; public $taxAmount; public $fullAmount; public $commandAmountPct; public $_tab_3_1_smallLabel = array('date', 'amount', 'paymentComplete', 'payment'); public $paymentDate; public $paymentAmount; public $paymentDone; public $_spe_paymentsList; public $paymentsCount; public $description; public $billingType; //public $_sec_BillLine; public $_BillLine = array(); public $_BillLine_colSpan = "2"; public $_sec_Link; public $_Link = array(); public $_Attachment = array(); public $_Note = array(); public $_nbColMax = 3; // Define the layout that will be used for lists private static $_layout = ' # ${id} ${reference} ${idClient} ${idProject} ${name} ${date} ${idRecipient} ${fullAmount} ${done} ${idle} '; private static $_fieldsAttributes = array('name' => 'required', 'id' => 'nobr', 'idStatus' => 'required', 'idBillType' => 'required', 'idProject' => 'required', 'billId' => 'hidden', 'taxAmount' => 'calculated,readonly', 'idPrec' => 'required', 'billingType' => 'hidden', 'fullAmount' => 'readonly', 'untaxedAmount' => 'readonly', "idle" => "nobr", "cancelled" => "nobr", 'paymentDueDate' => 'readonly', 'paymentsCount' => 'hidden' ); private static $_colCaptionTransposition = array('description' => 'comment', 'idContact' => 'billContact', 'idPaymentDelay' => 'paymentDelay', 'idDeliveryMode' => 'sendMode', "idUser" => "issuer", 'idResource' => 'responsible', 'paymentDone' => 'paymentComplete' ); private static $_databaseColumnName = array('taxPct' => 'tax'); public $_calculateForColumn = array("name" => "concat(coalesce(reference,''),' - ',name,' (',coalesce(fullAmount,0),')')"); /** ========================================================================== * Constructor * @param $id the id of the object in the database (null if not stored yet) * @return void */ function __construct($id = NULL, $withoutDependentObjects = false) { parent::__construct($id, $withoutDependentObjects); if (!$this->id) { $this->commandAmountPct = 100; } if ($this->done) { self::$_fieldsAttributes['idClient'] = 'readonly'; self::$_fieldsAttributes['idBillType'] = 'readonly'; self::$_fieldsAttributes['date'] = 'readonly'; self::$_fieldsAttributes['idProject'] = 'readonly'; self::$_fieldsAttributes['idRecipient'] = 'readonly'; self::$_fieldsAttributes['idContact'] = 'readonly'; self::$_fieldsAttributes['taxPct'] = 'readonly'; self::$_fieldsAttributes['idPaymentDelay'] = 'readonly'; } if (count($this->_BillLine)) { self::$_fieldsAttributes['idProject'] = 'readonly'; } if ($this->fullAmount) { $this->taxAmount = $this->fullAmount - $this->untaxedAmount; } if ($this->paymentDone) { self::$_fieldsAttributes['paymentDate'] = 'readonly'; self::$_fieldsAttributes['paymentAmount'] = 'readonly'; } if ($this->paymentsCount > 0) { self::$_fieldsAttributes['paymentDate'] = 'readonly'; self::$_fieldsAttributes['paymentAmount'] = 'readonly'; self::$_fieldsAttributes['paymentDone'] = 'readonly'; } } /** ========================================================================== * Destructor * @return void */ function __destruct() { parent::__destruct(); } // ============================================================================********** // GET STATIC DATA FUNCTIONS // ============================================================================********** /** ========================================================================== * Return the specific layout * @return the layout */ protected function getStaticLayout() { return self::$_layout; } /** ========================================================================== * Return the specific fieldsAttributes * @return the fieldsAttributes */ protected function getStaticFieldsAttributes() { return self::$_fieldsAttributes; } /** ============================================================================ * Return the specific colCaptionTransposition * @return the colCaptionTransposition */ protected function getStaticColCaptionTransposition($fld = null) { return self::$_colCaptionTransposition; } /** ======================================================================== * Return the specific databaseTableName * @return the databaseTableName */ protected function getStaticDatabaseColumnName() { return self::$_databaseColumnName; } /** ========================================================================= * control data corresponding to Model constraints * @param void * @return "OK" if controls are good or an error message * must be redefined in the inherited class */ public function control() { $result = ""; // When bill is done if ($this->done) { // some data is mandatory if (!$this->date) { $result.="
" . LocaleUtil::istanza()->i18n('messageMandatory', array(LocaleUtil::istanza()->i18n('colDate'))); } if (!trim($this->idClient)) { $result.="
" . LocaleUtil::istanza()->i18n('messageMandatory', array(LocaleUtil::istanza()->i18n('colIdClient'))); } if (!trim($this->idContact)) { $result.="
" . LocaleUtil::istanza()->i18n('messageMandatory', array(LocaleUtil::istanza()->i18n('colIdContact'))); } if (!trim($this->idRecipient)) { $result.="
" . LocaleUtil::istanza()->i18n('messageMandatory', array(LocaleUtil::istanza()->i18n('colIdRecipient'))); } // Lines must exist when bill is done if (!$this->id) { $result.="
" . LocaleUtil::istanza()->i18n('errorEmptyBill'); } else { $line = new BillLine(); $crit = array("refId" => $this->id); $lineList = $line->getSqlElementsFromCriteria($crit, false); if (count($lineList) == 0) { $result.="
" . LocaleUtil::istanza()->i18n('errorEmptyBill'); } } } $defaultControl = parent::control(); if ($defaultControl != 'OK') { $result.=$defaultControl; } if ($result == "") { $result = 'OK'; } return $result; } /** ========================================================================= * Overrides SqlElement::deleteControl() function to add specific treatments * @see persistence/SqlElement#deleteControl() * @return the return message of persistence/SqlElement#deleteControl() method */ public function deleteControl() { $result = ""; // Cannot delete done bill $status = new Status($this->idStatus); if ($status->setDoneStatus) { $result .= "
" . LocaleUtil::istanza()->i18n("errorDeleteDoneBill"); } // Cannot delete bill with lines /* $line = new BillLine(); $crit = array("refId"=>$this->id); $lineList = $line->getSqlElementsFromCriteria($crit,false); if (count($lineList)>0) { $result.="
" . LocaleUtil::istanza()->i18n('errorControlDelete') . "
 - " .LocaleUtil::istanza()->i18n('BillLine') . " (" . count($lineList) . ")";; ; } */ if (!$result) { $result = parent::deleteControl(); } return $result; } /** ========================================================================= * Overrides SqlElement::delete() function to add specific treatments * @see persistence/SqlElement#delete() * @return the return message of persistence/SqlElement#delete() method */ public function delete() { $result = parent::delete(); if (!strpos($result, 'id="lastOperationStatus" value="OK"')) { return $result; } return $result; } private function createTermBillLine(&$line, $bill_id, $term) { $billLine = new BillLine(); $billLine->refType = 'Bill'; $billLine->refId = $bill_id; $billLine->line = $line++; $billLine->quantity = 1; // $billLine->description = $term->description; Impostato al save // $billLine->detail; Impostato al save // $billLine->price = $term->amount; Impostato al save $billLine->idMeasureUnit = NULL; // $billLine->amount = $term->amount; Impostato al save $billLine->idTerm = $term->id; $billLine->idResource; $billLine->idActivityPrice = NULL; $billLine->startDate = NULL; $billLine->endDate = NULL; $billLine->extra = 0; $billLine->billingType = BillType::BILL_AT_TERMS; $result = $billLine->save(); if ($billLine->id) { $result = ''; // $term->idBill = $bill_id; ! Lo ha già fatto il save // $term->save(); } return $result; } private function createProdWorkBillLine(&$line, $bill_id, $billingType, $idResource, $idActivityPrice) { $billLine = new BillLine(); $billLine->refType = 'Bill'; $billLine->refId = $bill_id; $billLine->line = $line++; $billLine->quantity = 1; // $billLine->description = $term->description; Impostato al save // $billLine->detail; Impostato al save // $billLine->price = $term->amount; Impostato al save $billLine->idMeasureUnit = NULL; // $billLine->amount = $term->amount; Impostato al save $billLine->idTerm = null; $billLine->idResource = $idResource; $billLine->idActivityPrice = $idActivityPrice; $billLine->startDate = NULL; $billLine->endDate = NULL; $billLine->extra = 0; $billLine->billingType = $billingType; $result = $billLine->save(); if (!$billLine->id) { return $result; } if ($billLine->amount == 0) { $billLine->delete(); return false; } return ''; } private function createManualBillLine(&$line, $bill_id, $quantity, $price, $description) { $billLine = new BillLine(); $billLine->refType = 'Bill'; $billLine->refId = $bill_id; $billLine->line = $line++; $billLine->quantity = $quantity; $billLine->description = $description; $billLine->detail; $billLine->price = $price; $billLine->idMeasureUnit = 3; $billLine->amount = $quantity * $price; $billLine->idTerm = NULL; $billLine->idResource; $billLine->idActivityPrice = NULL; $billLine->startDate = NULL; $billLine->endDate = NULL; $billLine->extra = 0; $billLine->billingType = BillType::BILL_MANUAL; $result = $billLine->save(); if ($billLine->id) { $result = ''; } return $result; } private function createExpenseBillLine(&$line, $bill_id, $expense) { if ($expense->realAmount == 0) { return false; } $billLine = new BillLine(); $billLine->refType = 'Bill'; $billLine->refId = $bill_id; $billLine->line = $line++; $billLine->quantity = 1; $billLine->description = $expense->name . " Expense"; $billLine->detail; $billLine->price = $expense->realAmount; $billLine->idMeasureUnit = 1; $billLine->amount = $expense->realAmount; $billLine->idTerm = NULL; $billLine->idResource; $billLine->idActivityPrice = NULL; $billLine->startDate = $expense->realDate; $billLine->endDate = $expense->realDate; $billLine->extra = 0; $billLine->billingType = BillType::BILL_MANUAL; $result = $billLine->save(); if (!$billLine->id) { return $result; } $expense->idBill = $bill_id; $expense->save(); return ''; } private function createBill($project, $idBillType, $billingType) { $this->idProject = $project->id; $this->name = $project->name; $this->description = $project->description; $this->creationDate = date('Y-m-d'); $this->idClient = $project->idClient; $this->idUser = Session::istanza()->getCurrentUserId(); $this->idStatus = Status::STATUS_RECORDED; $this->idResource = $project->idResource; $this->reference = ''; // Cos'è ????? $this->idBillType = $idBillType; // FINAL_BILL COMPLETE_BILL $this->date = date('Y-m-d'); // ???? $this->idPaymentDelay = NULL; // Verrà impostato nel save o prendere dal project o no $this->paymentDueDate = NULL; $this->idRecipient = self::DEFAULT_RECIPIENT; $this->Origin = ''; // Cos'è ????? $this->billId = NULL; // Verrà impostato nel save $this->done = 0; $this->idle = 0; $this->cancelled = 0; $this->untaxedAmount = 0; // Verrà impostato nel save $this->taxPct = 0; // Verrà impostato nel save $this->taxAmount = 0; // ?? $this->fullAmount = 0; // Verrà impostato nel save $this->commandAmountPct; $this->paymentDate = NULL; $this->paymentAmount = NULL; $this->paymentDone = 0; $this->paymentsCount = 0; $this->billingType = $billingType; // BILL_AT_TERMS BILL_CAP_PROD_WORK BILL_PROD_WORK $this->idDeliveryMode = NULL; $this->sendDate = NULL; $this->idContact = $project->idContact; return $this->simpleSave(); // Per avere un id } public function billedUntaxedAmount($idProject) { $crit = array("idProject" => $idProject, "cancelled" => '0'); $billFinder = new Bill($idProject); $billList = $billFinder->getSqlElementsFromCriteria($crit, false); $billedAmount = 0; foreach ($billList as $bill) { $billedAmount += $bill->untaxedAmount; } return $billedAmount; } private function resultMessage($message, $value = 'INVALID') { $returnValue = '' . $message . ''; $returnValue .= ''; $returnValue .= ''; $returnValue .= ''; return $returnValue; } /** ========================================================================= * Overrides SqlElement::deleteControl() function to add specific treatments * @see persistence/SqlElement#deleteControl() * @return the return message of persistence/SqlElement#deleteControl() method */ /* * ========================================================================= * Overrides SqlElement::save() function to add specific treatments * @see persistence/SqlElement#save() * @return the return message of persistence/SqlElement#save() method */ public function billFromProject($idProject) { $created = false; if (trim($idProject) == '') { return $this->resultMessage("Manca id del Progetto"); } $project = new Project($idProject); if ($project->idProjectType == ProjectType::FIXED_PRICE) { $billingType = BillType::BILL_AT_TERMS; // BILL_AT_TERMS BILL_CAP_PROD_WORK BILL_PROD_WORK } else if ($project->idProjectType == ProjectType::TIME_AND_MATERIALS) { $billingType = BillType::BILL_PROD_WORK; // Da rivedere } else if ($project->idProjectType == ProjectType::CTAM) { $billingType = BillType::BILL_CAP_PROD_WORK; // Da rivedere } else { return $this->resultMessage("Non è possibile creare una fattura per questo tipo di progetto"); } $billedAmount = $this->billedUntaxedAmount($idProject); $billableAmountLeft = $project->ProjectPlanningElement->totalValidatedCost - $billedAmount; if ($billableAmountLeft <= 0) { return $this->resultMessage("Non è possibile creare una fattura per questo progetto : già fatturato l'importo validato"); } $bill_id = null; if ($project->idProjectType == ProjectType::FIXED_PRICE) { $termFinder = new Term(); $termList = $termFinder->getProjectTerms($idProject); if (count($termList) > 0) { $term = $termList[0]; if ($term->validatedAmount > $billableAmountLeft) { return $this->resultMessage("Non è possibile creare questa fattura : l'importo fissato per la scadenza supera l'importo residuo"); } else if ($term->validatedAmount == $billableAmountLeft) { $idBillType = $billedAmount == 0 ? BillType::COMPLETE_BILL : BillType::FINAL_BILL; // } else { $idBillType = BillType::PARTIAL_BILL; // } $result = $this->createBill($project, $idBillType, $billingType); if (!$this->id) { return $result; } $bill_id = $this->id; $line = 1; $result = $this->createTermBillLine($line, $bill_id, $term); if ($result != '') { return $result; } $created = true; } else if ($project->done) { $idBillType = $billedAmount == 0 ? BillType::COMPLETE_BILL : BillType::FINAL_BILL; // $result = $this->createBill($project, $idBillType, $billingType); if (!$this->id) { return $result; } $bill_id = $this->id; $line = 1; $quantity = 1; $price = $billableAmountLeft; $result = $this->createManualBillLine($line, $bill_id, $quantity, $price, $description); if ($result != '') { return $result; } $created = true; } else { $result = $this->resultMessage("Non esiste una scadenza per questo progetto. Crearla o chiudere il progetto"); } } else if ($project->idProjectType == ProjectType::TIME_AND_MATERIALS || $project->idProjectType == ProjectType::CTAM) { $affectationFinder = new Affectation(); $crit = array("idProject" => $idProject, "idle" => '0'); $affectationList = $affectationFinder->getSqlElementsFromCriteria($crit, false); $activitypriceFinder = new ActivityPrice(); $activitypriceList = $activitypriceFinder->getSqlElementsFromCriteria($crit, false); if (count($affectationList) == 0) { $result = $this->resultMessage("Impossibile creare la fattura per il lavoro :Nessuna risorsa coinvolta in questo progetto"); } else if (count($activitypriceList) == 0) { $result = $this->resultMessage("Impossibile creare la fattura per il lavoro :Nessun prezzo attività creato per questo progetto"); } else { $idBillType = BillType::PARTIAL_BILL; // $result = $this->createBill($project, $idBillType, $billingType); if (!$this->id) { return $result; } $bill_id = $this->id; $line = 1; foreach ($affectationList as $affectation) { foreach ($activitypriceList as $activityprice) { $idResource = $affectation->idResource; $idActivityPrice = $activityprice->id; $result = $this->createProdWorkBillLine($line, $bill_id, $billingType, $idResource, $idActivityPrice); if ($result !== false) { if ($result != '') { return $result; } $created = true; } } } } } // $quotation = SqlElement::getSingleSqlElementFromCriteria('Quotation', $crit, false); if ($project->ProjectPlanningElement->expenseAssignedAmount >= $project->ProjectPlanningElement->expenseValidatedAmount) { $expenseFinder = new Expense(); $crit = array("idProject" => $idProject, "cancelled" => '0', "idBill" => null); $expenseList = $expenseFinder->getSqlElementsFromCriteria($crit, false); if (count($expenseList) > 0) { if (!$bill_id) { $idBillType = BillType::PARTIAL_BILL; // $result = $this->createBill($project, $idBillType, $billingType); if (!$this->id) { return $result; } $bill_id = $this->id; } foreach ($expenseList as $expense) { $result = $this->createExpenseBillLine($line, $bill_id, $expense); if ($result !== false) { if ($result != '') { return $result; } $created = true; } } } } if ($created) { $result = $this->resultMessage("Bill $bill_id inserted", 'OK'); } else if ($result == '') { $result = $this->resultMessage("Bill $bill_id not inserted. No amount to bill"); } return $result; } /** ========================================================================= * Overrides SqlElement::save() function to add specific treatments * @see persistence/SqlElement#save() * @return the return message of persistence/SqlElement#save() method */ public function save() { $oldBill = $this->getOld(); // billingType $proj = new Project($this->idProject); $type = new ProjectType($proj->idProjectType); $this->billingType = $type->internalData; // Calclate bill id if ($this->done and ! $this->billId) { $numStart = GlbParameter::istanza()->getGlobalParameter('billNumStart'); $bill = new Bill(); $crit = array("done" => "1"); $billList = $bill->getSqlElementsFromCriteria($crit, false); $num = count($billList) + $numStart; $this->billId = $num; $this->setReference(); } // Get Client if (!trim($this->idClient)) { $this->idClient = $proj->idClient; } // get Contact if (!trim($this->idContact)) { $this->idContact = $proj->idContact; } // Get the tax from Client / Contact / Recipient if (trim($this->idClient)) { $client = new Client($this->idClient); if ($client->taxPct != '' and ! $this->taxPct) { $this->taxPct = $client->taxPct; } if (!trim($this->idPaymentDelay)) { $this->idPaymentDelay = $client->idPaymentDelay; } } if (trim($this->idRecipient)) { $recipient = new Recipient($this->idRecipient); if ($recipient->taxFree) { $this->taxPct = 0; } } if (trim($this->idPaymentDelay) and $this->date) { $delay = new PaymentDelay($this->idPaymentDelay); $date = GlbCalendar::istanza()->addDaysToDate($this->date, $delay->days); if ($delay->endOfMonth) { $date = date("Y-m-t", strtotime($date)); } $this->paymentDueDate = $date; } if ($this->paymentAmount == $this->fullAmount and $this->fullAmount > 0) { $this->paymentDone = 1; } // calculate amounts for bill lines $billLine = new BillLine(); $crit = array("refType" => "Bill", "refId" => $this->id); $billLineList = $billLine->getSqlElementsFromCriteria($crit, false); $amount = 0; foreach ($billLineList as $line) { $amount+=$line->amount; } $this->untaxedAmount = $amount; $this->fullAmount = $amount * (1 + $this->taxPct / 100); $this->retreivePayments(false); $result = parent::save(); return $result; } /** ========================================================================== * Return the validation sript for some fields * @return the validation javascript (for dojo frameword) */ public function getValidationScript($colName) { $colScript = parent::getValidationScript($colName); if ($colName == "untaxedAmount" || $colName == "taxPct") { $colScript .= ''; } else if ($colName == "idProject") { $colScript .= ''; } else if ($colName == "idClient") { $colScript .= ''; } return $colScript; } public function drawSpecificItem($item) { // $displayWidth = PrintUtil::istanza()->getDisplayWidth(); // $labelWidth = 175; // To be changed if changes in css file (label and .label) // $largeWidth = ( ($displayWidth + 30) / 2) - $labelWidth; $result = ""; if ($item == 'billingType') { $result .="
"; $result .=""; $printMode = PrintUtil::istanza()->getPrintMode(); if ($printMode) { $result.=LocaleUtil::istanza()->i18n('billingType' . $this->billingType); } else { /* $result .='billingType) { $result .=' value="' . LocaleUtil::istanza()->i18n('billingType'.$this->billingType) . '"'; } $largeWidth=setWidthPct($displayWidth, $print, $largeWidth, $this)/2; $result.=' style="width:100%;"'; $result.=' readonly="readonly"'; $result .='/>'; */ if ($this->billingType) { $result .= LocaleUtil::istanza()->i18n('billingType' . $this->billingType); } } $result .= '
'; } else if ($item == 'paymentsList') { $pay = new Payment(); $payList = $pay->getSqlElementsFromCriteria(array('idBill' => $this->id)); $result.='
'; $result.=''; foreach ($payList as $pay) { $result.=''; $result.=''; $result.=''; $result.=''; } $result.='
#' . HtmlUtil::htmlEncode($pay->id) . '   ' . HtmlUtil::htmlEncode($pay->name) . '
'; $result.='
'; } return $result; } public function simpleSave() { return parent::save(); } public function retreivePayments($save = true) { $pay = new Payment(); $payList = $pay->getSqlElementsFromCriteria(array('idBill' => $this->id)); $this->paymentsCount = count($payList); if (count($payList) == 0) { if ($save) { $this->simpleSave(); } return; } $this->paymentAmount = 0; $this->paymentDate = ''; $this->paymentDone = 0; foreach ($payList as $pay) { $this->paymentAmount+=$pay->paymentAmount; if ($pay->paymentDate > $this->paymentDate) $this->paymentDate = $pay->paymentDate; } if ($this->paymentAmount >= $this->fullAmount and $this->fullAmount > 0) $this->paymentDone = 1; if ($save) { $this->simpleSave(); } } } ?>