I know it has been asked before, but I canât get it to work - creating an invoice from a contract seems to be impossible. One suggested using the converToInvoice.php from the AOS_Quotes, but thatâs just a bit to technical for me.
What I need shouldnât be too difficult - creating a monthly invoice from the contract. Is there anyone out there willing to help me - if so, please let me know how much itâll cost. Itâll save me a horribly lot of monthly manual labor.
It is possible with few changes in code. if you wish trial and error here are some steps.
You need to create convert to invoice button, code reference you can get it from modules/AOS_Quotes/metadata/detailviewdefs.php and copy button code and add it to AOS_Contracts moduleâs metadata
Copy modules/AOS_Quotes/converToInvoice.php and paste it to your AOS_Contracts module and change the module reference
If you want to relate those invoice list with contract you need to create relationship from studio and It should be one contract have multiple invoices!
SuiteCRM is not an ERP, and it is not an accounting app. The Quotes and Invoices module is exactly that, a module.
On the other hand, the money you save on a single month of the monthly licenses of another program might be quite enough to pay for the necessary customizations to get what you want with SuiteCRM.
And in the end you can contribute that code to the Community and then, behold! SuiteCRM is a âfully functional open-sourceâ (until somebody comes up with the next requirement)
You are probably right, but as a small business the technology know-how or the budget is lacking to support these changes. From this perspective it should just work.
Nevertheless, the software is amazing. But unfortunately not for us.t work and is SuiteCRM possible not a sweet fit
I am also working on the topic âconverting an contract to invoiceâ.
My workflow: quote -> create contract -> convert invoice.
But there are still a few challenges from convert contract to invoice.
I already have created an button âcoverToInvoiceâ.
As soon as I press the âconvertToInvoiceâ button (from an contract), will opened an invoice.
Some information is taken from the contract, but unfortunately some is not.
I have graphed this for better understanding.
Youâre not retrieving account information anywhere in the code you pasted. Basically it doesnât get set for the $invoice. In fact, youâre setting billing_account and billing_contact of $rawRow to empty strings, so youâre getting exactly what is expected.
Dear TLi, many thanks for your kindly reply.
In the meantime I have got a little bit further. The products are included in the invoice - Iâm really happy about it
Unfortunately, I do not quite understand what you are saying with your kind advice.
I have modified the contact information accordingly:
âŚ
$rawRow[âcontactâ] = âcontactâ;
$rawRow[âaccountâ] = âaccountâ;
$rawRow[âbilling_address_streetâ] = âbilling_address_streetâ;
$rawRow[âbilling_accountâ] = âbilling_accountâ;
$rawRow[âbilling_contactâ] = âbilling_contactâ;
âŚ
The result look like this:
//Setting Group Line Items
$sql = âSELECT * FROM aos_line_item_groups WHERE parent_type = âAOS_Contractsâ AND parent_id = 'â.$contract->id."â AND deleted = 0";
I think in the long run youâd be better off completely redoing the conversion action using BeanFactory instead of direct queries and so on. IMO the one in SuiteCRM isnâ't very well made. But that is for another discussion.
For the account and contact values I think youâre actually using wrong field names. IIRC you need billing_account_id instead of billing_account (check database tables for the correct names). The thing is that even though in the view you see the name of an account and/or contact, SuiteCRM is dealing with their UUIDs. So make sure youâre using the correct field names.
Also at $rawRow[âbilling_address_streetâ] = âbilling_address_streetâ; you are actually setting the value as a string called billing_address_street. Are you sure you shouldnât be looking for a variable or object property?
If neither helps. I can later check how Iâve recreated the conversion in the past and see if I can give any other pointers. I remember I ended up pretty muchredoing the conversion altogether.
I have now tested a few things:
âŚ
$rawRow[âcontact_idâ] = ââ;
$rawRow[âcontract_accountâ] = ââ;
$rawRow[âcontract_account_idâ] = ââ;
$rawRow[âbilling_address_streetâ] = ââ;
$rawRow[âbilling_accountâ] = âbilling_account_idâ;
$rawRow[âbilling_contactâ] = âbilling_contact_idâ;
$rawRow[âdelivery_address_auftrag_câ] = ââ;
âŚ
and some other variations, but the result is always the same
It would be very kind if you could help further.
Many thanks!
You gave me a good hint about the database. Now, I have compared aos_quotes and aos_contracts in the database. In the aos_contracts table there are no fields: billing_account_id, billing_contact_id, billing_address_street, etc. I think thatâs the reason. What is your opinion?
Here my aos_quotes:
The contract doesnât record accountâs address; if you make a PDF template, the up-to-date address details are fetched from the Account and Contactâs individual records. Contract only keeps track of the UUIDs.
Iâm assuming (canât check right now) that in the contract DB table there is account_id or something like that (and contact_id) - basically the Account(/Contact) you are connecting the contract with. What you should do is use the BeanFactory to get the correct account bean and populate the Invoiceâs billing details from there. Hereâs a quick and scratchy pseudocode for illustration; Iâm letting you figure out the rest :
And so on. While you are at it, consider changing all work to use BeanFactory - thatâs the recommended way nowadays and good practice for you. Itâs also simpler IMO.
I spent now 5 days, to transferring the contract address (billing_account and billing_contact) datas to the respective invoice.
I do not understand why I cannot transfer this account data from the contract to the invoice. All other data is transferred from the contract to the invoice.
I also worked with BeanFactory. But apparently I lack understanding Probably it´s just missing one single line or tow, to the destination.
If I enter and save the address manually, so I can see the addresse (not the account name or contact name) in the table aos_contracts_cstm (via phpmyadmin).
The solution is a combination of createContract.php and converToInvoice.php.
The products, the company and the contact person are transferred from the contract to the invoice. It wasnât implemented with BeanFactory, I couldnât do it - itâs too difficult for me.
Now I can create an invoice from an contract:
filename: converToInvoice.php
<?php
/* ... */
if (!(ACLController::checkAccess('AOS_Invoices', 'edit', true))) {
ACLController::displayNoAccess();
die;
}
// require_once('modules/AOS_Contracts/AOS_Contracts.php');
// require_once('modules/AOS_Invoices/AOS_Invoices.php');
global $timedate;
//Setting values in Contracts
$contract = new AOS_Contracts();
$contract->retrieve($_REQUEST['record']);
//Setting Invoices Values
$invoice = new AOS_Invoices();
$invoice->name = $contract->name;
$invoice->assigned_user_id = $contract->assigned_user_id;
$invoice->total_contract_value = format_number($contract->total_amount);
$invoice->billing_account_id = $contract->contract_account_id;
$invoice->billing_contact_id = $contract->contact_id;
$invoice->total_amt = $contract->total_amt;
$invoice->subtotal_amount = $contract->subtotal_amount;
$invoice->discount_amount = $contract->discount_amount;
$invoice->tax_amount = $contract->tax_amount;
$invoice->shipping_amount = $contract->shipping_amount;
$invoice->shipping_tax = $contract->shipping_tax;
$invoice->shipping_tax_amt = $contract->shipping_tax_amt;
$invoice->total_amount = $contract->total_amount;
$invoice->currency_id = $contract->currency_id;
$invoice->save();
$group_id_map = array();
//Setting Group Line Items
$sql = "SELECT * FROM aos_line_item_groups WHERE parent_type = 'AOS_Contracts' AND parent_id = '".$contract->id."' AND deleted = 0";
$result = $this->bean->db->query($sql);
while ($row = $this->bean->db->fetchByAssoc($result)) {
$old_id = $row['id'];
$row['id'] = '';
$row['parent_id'] = $invoice->id;
$row['parent_type'] = 'AOS_Invoices';
if ($row['total_amt'] != null) {
$row['total_amt'] = format_number($row['total_amt']);
}
if ($row['discount_amount'] != null) {
$row['discount_amount'] = format_number($row['discount_amount']);
}
if ($row['subtotal_amount'] != null) {
$row['subtotal_amount'] = format_number($row['subtotal_amount']);
}
if ($row['tax_amount'] != null) {
$row['tax_amount'] = format_number($row['tax_amount']);
}
if ($row['subtotal_tax_amount'] != null) {
$row['subtotal_tax_amount'] = format_number($row['subtotal_tax_amount']);
}
if ($row['total_amount'] != null) {
$row['total_amount'] = format_number($row['total_amount']);
}
$group_invoice = new AOS_Line_Item_Groups();
$group_invoice->populateFromRow($row);
$group_invoice->save();
$group_id_map[$old_id] = $group_invoice->id;
}
//Setting Line Items
$sql = "SELECT * FROM aos_products_quotes WHERE parent_type = 'AOS_Contracts' AND parent_id = '".$contract->id."' AND deleted = 0";
$result = $this->bean->db->query($sql);
while ($row = $this->bean->db->fetchByAssoc($result)) {
$row['id'] = '';
$row['parent_id'] = $invoice->id;
$row['parent_type'] = 'AOS_Invoices';
if ($row['product_cost_price'] != null) {
$row['product_cost_price'] = format_number($row['product_cost_price']);
}
$row['product_list_price'] = format_number($row['product_list_price']);
if ($row['product_discount'] != null) {
$row['product_discount'] = format_number($row['product_discount']);
$row['product_discount_amount'] = format_number($row['product_discount_amount']);
}
$row['product_unit_price'] = format_number($row['product_unit_price']);
$row['vat_amt'] = format_number($row['vat_amt']);
$row['product_total_price'] = format_number($row['product_total_price']);
$row['product_qty'] = format_number($row['product_qty']);
$row['group_id'] = $group_id_map[$row['group_id']];
$prod_invoice = new AOS_Products_Quotes();
$prod_invoice->populateFromRow($row);
$prod_invoice->save();
}
//Setting invoice contract relationship
require_once('modules/Relationships/Relationship.php');
$key = Relationship::retrieve_by_modules('AOS_Contracts', 'AOS_Invoices', $GLOBALS['db']);
if (!empty($key)) {
$contract->load_relationship($key);
$contract->$key->add($invoice->id);
}
ob_clean();
header('Location: index.php?module=AOS_Invoices&action=EditView&record='.$invoice->id);
//
I hope it will help someone, who is also looking for this solution.