When creating an invoice with SugarCRM, in the invoice detail there's number of unit and unit price. I would like to populate the field line price automatically, which is simply the product of those two fields above.
Here is what I added in the custom/modules/C_Inc_Invoice_Detail directory :
logic_hook.php
<?php
$hook_version = 1;
$hook_array = array();
$hook_array['after_save'] = array();
$hook_array['after_save'][] = array(
1,
'Auto Fill Line price',
'custom/modules/C_Inv_Invoice_Detail/autofilllineprice.php',
'AutoFillLinePrice',
'autofilllineprice'
);
?>
and the autofilllineprice.php :
<?php
//prevents directly accessing this file from a web browser
if
(!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
class AutoFillLinePrice {
function autofilllineprice($bean, $event, $arguments){
$line_price = $bean->unit_price * $bean->number_units;
}
}
?>
Could you advise ?
This post does not answer this question directly, but it documents the steps involved in accomplishing a similar requirement. The Accounts module in SugarCE-6.5.22 has a field Annual Revenue and it's displayed in the DetailView as shown below.
The following are the steps involved in adding a new field that displays the value of this field converted to some other currency.
The first step is to create a non-db field that will hold the value of this new currency. For this, we need to create two files, one that defines the field("custom_fields.php") and the other that defines a language specific dispplay value for this field("en_us_custom_fields.php"). These two files are to be created in the below mentioned location. Please create the required directory structure if not present already.
custom\Extension\modules\Accounts\Ext\Vardefs\custom_fields.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
$dictionary['Account']['fields']['annual_revenue_inr'] = array(
'name' => 'annual_revenue_inr',
'vname' => 'LBL_ANNUAL_REVENUE_INR',
'label'=>'LBL_ANNUAL_REVENUE_INR',
'type' => 'name',
'module' => 'Accounts',
'source' => 'non-db',
'studio' => array('detailview'=>true),
'default_value' => '',
'help' => 'Annual Revenue(INR)',
'comment' => 'Annual Revenue(INR)',
'reportable' => true,
'audited' => false,
'duplicate_merge' => false,
'importable' => 'true',
);
?>
custom\Extension\modules\Accounts\Ext\Language\en_us_custom_fields.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
$mod_strings['LBL_ANNUAL_REVENUE_INR'] = 'Annual Revenue(INR)';
?>
After adding these two files, we need to run Admin-->Repair-->Quick Repair and Rebuild. After it's complete, if we open Admin-->Studio and expand Accounts-->Layouts-->DetailView, we should see our newly created field available there. We can drag and drop it inside the layout wherever we want it to appear and click Save & Deploy.
Now, this new field should be visible in the detail view of the account.
The next task is to populate the value for this new currency. This can be achieved using logic hooks provided by SugarCRM. We need to compute the value for this field everytime after an account data is retrieved from database. The after_retrieve event can be used for this. First, let's create a php file("annual_revenue_hook.php") with code that computes the value of this new currency field in the following location.
custom\Extension\modules\Accounts\Ext\hooks\annual_revenue_hook.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
class AnnualRevenue {
function computeAnnualRevenueINR($bean, $event, $arguments){
$bean->annual_revenue_inr = $bean->annual_revenue * 100;
}
}
?>
To register the above hook, we need to edit the logic_hooks.php file of the module and add the following lines:
custom\modules\Accounts\logic_hooks.php
//Create a new array that holds after_retrieve event hooks if not present already
$hook_array['after_retrieve'] = Array();
//Register our annual revenue hook for computing new currency value
$hook_array['after_retrieve'][]= Array(1, 'Compute Annual Revenue in INR', 'custom/Extension/modules/Accounts/Ext/hooks/annual_revenue_hook.php','AnnualRevenue', 'computeAnnualRevenueINR');
After completing these steps, we should see the value of the new currency populated in the detail view as shown below:
It's also possible to get data from associated modules. For example, let's say we need to calculate the sum of all Opportunities associated with this Account and add to our new field. The following are the steps to accomplish it:
The first step is to get the relationship information between the modules, in this case between Accounts and Opportunities. We need to open the file modules\Accounts\vardefs.php and search for Opportunities. It should give us the following information.
'opportunities' =>
array (
'name' => 'opportunities',
'type' => 'link',
'relationship' => 'accounts_opportunities',
'module'=>'Opportunities',
'bean_name'=>'Opportunity',
'source'=>'non-db',
'vname'=>'LBL_OPPORTUNITY',
),
Then, we can open Admin-->Studio, expand Accounts-->Relationships and find the type of relationship as shown below:
Now that we have identified the relationship information, we can edit our existing hook as shown below:
custom\Extension\modules\Accounts\Ext\hooks\annual_revenue_hook.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
class AnnualRevenue {
function computeAnnualRevenueINR($bean, $event, $arguments){
$bean->annual_revenue_inr = $bean->annual_revenue * 100;
$bean->load_relationship('opportunities');
$opportunities = $bean->opportunities->getBeans();
//Every account has multiple opportunities i.e array of Opportunity
foreach($opportunities as $opportunity){
$bean->annual_revenue_inr = $bean->annual_revenue_inr + $opportunity->amount;
}
}
}
?>
The above code should now multiply annual_revenue by 100 and also sum up all the associated Opportunities with it to calculate the value of annual_revenue_inr.
Related
The app I'm working on (an order form) allows the user to enter multiple sub-records within an iframe. These sub-records are joined to the main record via a foreign key.
main_records line_items
----------- ----------
id int(11) PK etc. id int(11) PK etc.
main_record_id (FK)
I need the app to check whether at least one line item exists within this iframe before form submission. I would like to take advantage of the $validate functionality within the model, but I'm unsure how to proceed. Here's what I've tried in the Main model:
App::uses('AppModel', 'Model', 'LineItem');
public $hasMany = array(
'LineItem' => array(
'className' => 'LineItem',
'foreignKey' => 'main_record_id',
'dependent' => false
)
);
public $validate = array(
'main_record_id' = array(
'allowEmpty' => false,
'rule' => 'checkForLineItem',
'message' => 'You must enter at least one line item!'
)
);
//Check to make sure there is at least one line item before saving changes/submitting for approval
function checkForLineItem($id) {
$lines = $this->LineItem->find('all', array(
'fields' => array('LineItem.main_record_id'),
'conditions' => array('LineItem.main_record_id'=>$id, 'LineItem.deleted_record'=>0))
);
if(!empty($lines)) {
return true;
} else {
return false;
}
}
I also track whether the line item has been deleted. If it has, then it is not added to $lines.
I know I can accomplish this in the Controller, but as far as I know, that would require the form to post, and the user would lose any changes upon postback (I haven't yet implemented jQuery on this form). Am I on the right track with how to do this? What changes should I make to get this to work?
Your code looks about right, but validation indeed happens in form submit. If you want to check it prior to that you have to do in JavaScript (jquery). E.g. create a controller action that return if there are existing line items for given main record id and call it via AJAX.
I'm planning to build an extension like Shopping Cart, Price Rule, or Catalog Price Rule.
I've already tried to learn something from existing Magento code, that you can see on:
app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Conditions.php
To show a Conditions Rule field, I've tried to add this script, but it didn't work properly
$fieldset->addField('conditions', 'text', array(
'name' => 'conditions',
'label' => Mage::helper('salesrule')->__('Conditions'),
'title' => Mage::helper('salesrule')->__('Conditions'),
))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/conditions'));
The question is:
How to display the conditional field properly on my custom field?
How to apply rule conditions on the front-end?
Thanks in advance.
update,
take a look at my screenshot
https://docs.google.com/file/d/0BwLN4KpQhoGbU181R0ZKanJSdVE/edit?usp=drivesdk
this is my form.php:
<?php
class KS_Kscoba_Block_Adminhtml_Tcoba_Edit_Tab_Form
extends Mage_Adminhtml_Block_Widget_Form
/*
extends Mage_Adminhtml_Block_Widget_Form
implements Mage_Adminhtml_Block_Widget_Tab_Interface
*/
{
protected function _prepareForm()
{
$model = Mage::registry('current_promo_quote_rule');
$form = new Varien_Data_Form();
$this->setForm($form);
$fieldset = $form->addFieldset("kscoba_form", array("legend"=>Mage::helper("kscoba")->__("Item information")));
$fieldset->addField("kolom1", "text", array(
"label" => Mage::helper("kscoba")->__("Kolom 1"),
"name" => "kolom1",
));
$fieldset->addField('kolom2', 'select', array(
'label' => Mage::helper('kscoba')->__('Kolom 2'),
'values' => KS_Kscoba_Block_Adminhtml_Tcoba_Grid::getValueArray1(),
'name' => 'kolom2',
));
/*
problem start here
*/
$renderer = Mage::getBlockSingleton('adminhtml/widget_form_renderer_fieldset')
->setTemplate('promo/fieldset.phtml')
->setNewChildUrl($this->getUrl('*/promo_quote/newConditionHtml/form/rule_conditions_fieldset'));
$fieldset = $form->addFieldset('conditions_fieldset', array(
'legend'=>Mage::helper('salesrule')->__('Apply the rule only if the following conditions are met (leave blank for all products)')
))->setRenderer($renderer);
$fieldset->addField('conditions', 'text', array(
'name' => 'conditions',
'label' => Mage::helper('salesrule')->__('Conditions'),
'title' => Mage::helper('salesrule')->__('Conditions'),
))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/conditions'));
if (Mage::getSingleton("adminhtml/session")->getTcobaData())
{
$form->setValues(Mage::getSingleton("adminhtml/session")->getTcobaData());
Mage::getSingleton("adminhtml/session")->setTcobaData(null);
}
elseif(Mage::registry("tcoba_data")) {
$form->setValues(Mage::registry("tcoba_data")->getData());
}
return parent::_prepareForm();
}
}
am I missing something?
1. Conditions Field
I may be overlooking another issue, but when I tested your form.php, the conditions field was missing because Mage::registry('current_promo_quote_rule') was undefined. The conditions field appeared on the page after I populated $model with a Mage_SalesRule_Model_Rule object.
Magento 1.8 registers the current_promo_quote_rule in _initRule() and editAction() of the Mage_Adminhtml_Promo_QuoteController (app/code/core/Mage/Adminhtml/controllers/Promo/QuoteController.php).
2. Frontend
Using shopping cart price rules as an example, the discounted price is applied in the frontend through the checkout module.
Mage/Checkout/controllers/CartController.php has a couponPostAction() function which is called when the user submits a coupon code from the cart or checkout page. This function gets the cart's Mage_Sales_Model_Quote object, sets the coupon code on that object, and refreshes the totals of each item using the collectTotals() function of Mage_Sales_Model_Quote.
The quote object's collectTotals() gets the related Mage_Sales_Model_Quote_Address objects and calls their collectTotals() functions. Those functions get each of the collector objects associated with the address and call its collect() method.
One of those collector objects is a Mage_SalesRule_Model_Quote_Discount, whose collect() method gets each Mage_Sales_Model_Quote_Item associated with this address, then calculates and stores its discount using a Mage_SalesRule_Model_Validator.
The specific logic in the conditions is read and applied deeper in the SalesRule module.
Hello I want to assign multiple groups to particular customer like "Rajat the customer" belogs to "Wholesale,retailer,electric". actually I saw the same thread on Multiple customer groups per customer but it is not helpful does there any update to make this change happen.
I am stuck what should I do because there aren't any extension available with the same functionality?
I found the solution,
First of all go to database and click on the eav_attribute and then search for group_id in the attribute code field and edit this record.
now Step 1:-
change frontend_input from select to multiselect.
step 2:-
change backend_type from static to varchar.
although it is not standard way but it worked for me. :)
PS. I'm using magento 1.7.0.2 community version.
Rajat Modi's solution worked pretty well for me thank you but doing this did break the display of the groups column on the customer grid if more than one is selected, plus broke the ability to filter customers by group.
To fix that, create this file to use as the renderer for customer groups: /app/code/local/Mage/Adminhtml/Block/Customer/Renderer/Group.php
<?php
class Mage_Adminhtml_Block_Customer_Renderer_Group
extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract {
public function render(Varien_Object $row)
{
$value = $row->getData($this->getColumn()->getIndex());
$groups = Mage::getModel('customer/group')->getCollection()
->addFieldToFilter('customer_group_id', array('in' => explode(',', $value)));
$groupNames = array();
foreach ($groups as $group)
{
$groupNames[] = $group->getCustomerGroupCode();
}
return implode(', ', $groupNames);
}
}
Then override /app/code/core/Mage/Adminhtml/Block/Customer/Grid.phpenter code here (copy it to /app/code/local/Mage/Adminhtml/Block/Customer/Grid.php)
In the _prepareColumns() function, change this (around line 95):
$this->addColumn('group', array(
'header' => Mage::helper('customer')->__('Group'),
'width' => '100',
'index' => 'group_id',
'type' => 'options',
'options' => $groups,
));
to this:
$this->addColumn('group_id', array(
'header' => Mage::helper('customer')->__('Group'),
'width' => '100',
'index' => 'group_id',
'type' => 'options',
'options' => $groups,
'renderer' => 'Mage_Adminhtml_Block_Customer_Renderer_Group',
'filter_condition_callback' => array($this, '_filterGroupCondition')
));
then it will use that class for rendering groups on the grid.
Also in the _prepareCollection() function, around line 52 find ->addAttributeToSelect('group_id') and add after: ->addAttributeToSelect('customer_group_id')
Having multiple groups per customer also seems to interfere with tiered pricing (where a product has a different price depending on customer group). To fix that on the frontend display...
Fix for customer group-based product pricing tiers when calculating on the front-end:
In /app/code/core/Mage/Catalog/Model/Product/Type/Price.php
Around line 138, FIND:
$customerGroup = $this->_getCustomerGroupId($product);
ADD AFTER:
$customerGroups = explode(',',$customerGroup);
FIND:
if ($groupPrice['cust_group'] == $customerGroup && $groupPrice['website_price'] < $matchedPrice) {
REPLACE WITH:
if (in_array($groupPrice['cust_group'],$customerGroups) && $groupPrice['website_price'] < $matchedPrice) {
Do the same thing in /app/code/core/Mage/Bundle/Model/Product/Price.php if you use bundles.
I do not yet have a fix for displaying the customer group tier price when creating an order or reorder from the backend dashboard - they just show up the standard product prices.
Finally, when figuring all this out we did have some instances where mgnt_catalog_product_entity_group_price got emptied and I'm still not sure why it happened, so do make sure to take backups. For that table I restored it from an SQL backup, but re-indexing things and maybe flushing the Magento cache is also often required when getting into this stuff.
When doing things such as searching for customers by group programmatically in your own scripts or modules you may have to take into account that it is now a multiselect for example by doing things like this:
$allowedGroups = array(
array(
"finset" => array(10)
),
array(
"finset" => array(42)
)
);
$collection = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('group_id', $allowedGroups);
Although I'm not sure that that piece of code will work right until all the customers have rows in the mgnt_customer_entity_varchar table which is where the new value for a customer's groups is stored when there are more than one group selected. Only a single group ID remains stored in mgnt_customer_entity as that field isn't varchar.
For that reason be aware that yes it can affect modules which extend or use the functionality of customer groups.
Background: In Drupal 7, I have created a form with CCK (aka the Field UI). I used the Field group module to create a fieldgroup, but I need it to be conditional, meaning it will only display depending on a previous answer.
Previous research: To create a conditional field, you can use hook_form_alter() to edit the #states attribute like so:
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'person_info_node_form') {
// Display 'field_maiden_name' only if married
$form['field_maiden_name']['#states'] = array(
'visible' => array(
':input[name="field_married[und]"]' => array('value' => 'Yes'),
),
);
}
}
However, there seems to be no way to use the States API for fieldgroups. One thing to note is that, while fields are stored in $form, fieldgroups are stored in $form['#groups'] as well as in $form['#fieldgroups']. I don't know how to distinguish between these, and with this in mind, I have tried to apply a #states attribute to a fieldgroup in the same manner as above. However, it only produces server errors.
Question: Is there a way to make a fieldgroup display conditionally using the States API or some alternative approach?
you have to use the hook_field_group_build_pre_render_alter()
Simply :
function your_module_field_group_build_pre_render_alter(&$element) {
$element['your_field_group']['#states'] = array(
'visible' => array(
':input[name="field_checkbox"]' => array('checked' => TRUE),
),
);
}
This works perfecly. If the group A is in an another group, do this
$element['groupA']['groupB']['#states'] etc....
You may need to add an id attribute if none exists:
$element['your_field_group']['#attributes']['id'] = 'some-id';
$element['yout_field_group']['#id'] = 'some-id';
Here's the simplest solution I came up with. There are essentially 2 parts to this: (1.) programmatically alter the display of the form, and (2.) use the GUI to alter the display of the content.
(1.) First, I used hook_form_alter() to programmatically create the conditional fieldset and add existing fields to it. The code is shown below.
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'FORM_ID_node_form') {
// programmatically create a conditional fieldset
$form['MYFIELDSET'] = array( // do NOT name the same as a 'Field group' fieldset or problems will occur
'#type' => 'fieldset',
'#title' => t('Conditional fieldset'),
'#weight' => intval($form['field_PARENT']['#weight'])+1, // put this fieldset right after it's "parent" field
'#states' => array(
'visible' => array(
':input[name="field_PARENT[und]"]' => array('value' => 'Yes'), // only show if field_PARENT == 'Yes'
),
),
);
// add existing fields (created with the Field UI) to the
// conditional fieldset
$fields = array('field_MYFIELD1', 'field_MYFIELD2', 'field_MYFIELD3');
$form = MYMODULE_addToFieldset($form, 'MYFIELDSET', $fields);
}
}
/**
* Adds existing fields to the specified fieldset.
*
* #param array $form Nested array of form elements that comprise the form.
* #param string $fieldset The machine name of the fieldset.
* #param array $fields An array of the machine names of all fields to
* be included in the fieldset.
* #return array $form The updated form.
*/
function MYMODULE_addToFieldSet($form, $fieldset, $fields) {
foreach($fields as $field) {
$form[$fieldset][$field] = $form[$field]; // copy existing field into fieldset
unset($form[$field]); // destroy the original field or duplication will occur
}
return $form;
}
(2.) Then I used the Field group module to alter the display of the content. I did this by going to my content type and using the 'Manage display' tab to create a field group and add my fields to it. This way, the fields will appear to be apart of the same group on both the form and the saved content.
Maybe you can try to look at the code of this module to help you find an idea.
In the magento system, I added the columns subscriber_firstname and subscriber_lastname to the newsletter_subscriber db table.
In the admin area of magento, I want the Newsletter>Newsletter Subscribers grid table to show:
customer first name if it exists, otherwise show newsletter_subscriber.subscriber_firstname if it exists, otherwise show nothing
customer last name if it exists, otherwise show newsletter_subscriber.subscriber_lastname if it exists, otherwise show nothing
Which magento files do I need to edit to make this work? How do I go about editing the files to make this work?
app/code/core/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php
You'll want to condition this based off if subscriber_firstname or subscriber_lastname have values or not:
$this->addColumn('subscribername', array(
'header' => Mage::helper('newsletter')->__('Subscriber First Name'),
'index' => 'subscriber_firstname',
'default' => '----'
));
Also, make sure to make a copy of the core files and NOT edit them directly!
the quick and easy solution is to create a column render and select the correct field based on the subscriber type e.g.
app/code/local/Mage/Adminhtml/Block/Newsletter/Subscriber/Renderer/FirstName.php
class Mage_Adminhtml_Block_Newsletter_Subscriber_Renderer_FirstName extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract {
public function render(Varien_Object $row) {
$value = '';
if ($row->getData('type') == 2) {
$value = $row->getData('customer_firstname');
}
else {
$value = $row->getData('subscriber_firstname');
}
return $value;
}
}
then add your render to a local copy of the subscriber grid class
app/code/local/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php
$this->addColumn('firstname', array(
'header' => Mage::helper('newsletter')->__('First Name'),
'index' => 'customer_firstname',
'default' => '----',
'renderer' => 'Mage_Adminhtml_Block_Newsletter_Subscriber_Renderer_FirstName'
));
Note. the search and sort will not work on the subscriber name fields, to get this working you will need to extend app/code/core/Mage/Newsletter/Model/Mysql4/Subscriber/Collection.php