Modified customer merge functionality to leave everything from the destination customer in-tact, and simply add on contacts from the source customer, if requested. This simplifies things significantly, and also the paradigm shift of starting the operation from the destination customer allows us to merge multiple customers into one with ease (no need to dig around for each source customer before clicking merge)

git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@995 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
abijah
2010-07-02 20:52:00 +00:00
parent 34844760e8
commit 11aacd5803
4 changed files with 72 additions and 177 deletions

View File

@@ -466,9 +466,9 @@ class CustomersController extends AppController {
$customer = $customer['Customer']; $customer = $customer['Customer'];
if (empty($customer)) if (empty($customer))
$this->INTERNAL_ERROR("Customer $id does not exist"); $this->INTERNAL_ERROR("Customer $id does not exist");
$this->set('src_customer', $customer); $this->set('dst_customer', $customer);
$this->set('src_name', $customer['name']); $this->set('dst_name', $customer['name']);
$this->set('src_id', $id); $this->set('dst_id', $id);
} }
else { else {
$this->INTERNAL_ERROR("Merge called with invalid customer"); $this->INTERNAL_ERROR("Merge called with invalid customer");
@@ -483,8 +483,7 @@ class CustomersController extends AppController {
$post = $this->params['form']; $post = $this->params['form'];
$this->Customer->merge($post['dst-id'], $post['src-id'], $this->Customer->merge($post['dst-id'], $post['src-id'],
unserialize($post['contact-ids']), unserialize($post['contact-ids']));
$post['primary-contact-id']);
$this->redirect(array('action'=>'view', $post['dst-id'])); $this->redirect(array('action'=>'view', $post['dst-id']));
} }

View File

@@ -20,7 +20,13 @@ class Customer extends AppModel {
), ),
'Lease', 'Lease',
'StatementEntry', 'StatementEntry',
'ContactsCustomer', 'ContactsCustomer' => array(
// It would be nice to claim a dependency here, which would
// simplify deletion of a customer. However, for this to work
// Cake must have a primaryKey as a single field. This table
// makes use of a complex key, so we're out of luck.
/* 'dependent' => true, */
),
'Transaction', 'Transaction',
'Tender', 'Tender',
@@ -290,91 +296,54 @@ class Customer extends AppModel {
* - Merges two customers into one * - Merges two customers into one
*/ */
function merge($dst_id, $src_id, $contacts, $primary_contact_id) { function merge($dst_id, $src_id, $contacts) {
$this->prEnter(compact('dst_id', 'src_id', 'contacts', 'primary_contact_id')); $this->prEnter(compact('dst_id', 'src_id', 'contacts'));
$contacts = array_unique($contacts, SORT_NUMERIC);
if (!in_array($primary_contact_id, $contacts))
return $this->prReturn(false);
$all_contacts = array();
$result = $this->find('all',
array('link' => array('ContactsCustomer'),
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
'conditions' => array(array('id' => $src_id,
'ContactsCustomer.active' => true))));
$this->pr(17, compact('result'));
foreach ($result AS $contact) {
$this->pr(17, compact('contact'), "Add contact");
$all_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
}
// Get the entire list of destination customer contacts
$dst_contacts = array();
$result = $this->find('all', $result = $this->find('all',
array('link' => array('ContactsCustomer'), array('link' => array('ContactsCustomer'),
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'), 'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
'conditions' => array(array('id' => $dst_id, 'conditions' => array(array('id' => $dst_id,
'ContactsCustomer.active' => true)))); 'ContactsCustomer.active' => true))));
/* array('link' => array('Contact'), */
/* 'fields' => array('Contact.id'), */
/* 'conditions' => array(array('Customer.id' => $src_id)))); */
$this->pr(17, compact('result'));
foreach ($result AS $contact) { foreach ($result AS $contact) {
$this->pr(17, compact('contact'), "Add contact"); $dst_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
$all_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
} }
$this->pr(17, compact('dst_contacts'));
$this->pr(17, compact('all_contacts')); // Get the entire list of source customer contacts
$src_contacts = array();
$result = $this->find('all',
array('link' => array('ContactsCustomer'),
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
'conditions' => array(array('id' => $src_id,
'ContactsCustomer.active' => true))));
foreach ($result AS $contact) {
$src_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
}
$this->pr(17, compact('src_contacts'));
foreach ($contacts AS $cid) { // Verify the contacts list are all valid source customer contacts
if (!array_key_exists($cid, $all_contacts)) foreach ($contacts AS $contact_id) {
if (!array_key_exists($contact_id, $src_contacts))
return $this->prReturn(false); return $this->prReturn(false);
} }
$this->id = $dst_id; // Remove any contacts which are already destination customer contacts
$this->recursive = -1; $contacts = array_diff($contacts, array_keys($dst_contacts));
//$this->recursive = 1;
$this->read();
$this->pr(17, $this->data); // For now, we'll assume the operation will succeed.
if (!empty($primary_contact_id))
$this->data['Customer']['primary_contact_id'] = $primary_contact_id;
$this->data['Contact'] = array();
foreach ($contacts AS $contact_id)
$this->data['Contact'][] = array('id' => $contact_id,
'ContactsCustomer' =>
array('customer_id' => $dst_id) +
$all_contacts[$contact_id]);
/* $this->data['ContactsCustomer'] = array(); */
/* foreach ($contacts AS $contact_id) { */
/* $this->data['ContactsCustomer'][] = */
/* //array('ContactsCustomer' => */
/* array('customer_id' => $dst_id) + */
/* $all_contacts[$contact_id] */
/* //); */
/* } */
$this->pr(17, $this->data);
/* $this->ContactsCustomer->deleteAll */
/* (array('customer_id' => $id), false); */
//$this->recursive = 1;
if (!$this->saveAll($this->data, array('validate' => false))) {
return $this->prReturn(false);
}
// At this point, since we've saved data to customer,
// we'll proceed forward as much as possible, even
// if we encounter an error. For now, we'll assume
// the operation will succeed.
$ret = true; $ret = true;
// Add each desired source customer contact to the destination customer
foreach ($contacts AS $contact_id) {
$CM = new ContactsCustomer();
if (!$CM->save(array('customer_id' => $dst_id)
+ $src_contacts[$contact_id], false)) {
$ret = false;
}
}
$this->Lease->updateAll $this->Lease->updateAll
(array('Lease.customer_id' => $dst_id), (array('Lease.customer_id' => $dst_id),
array('Lease.customer_id' => $src_id) array('Lease.customer_id' => $src_id)
@@ -398,23 +367,31 @@ class Customer extends AppModel {
// Make sure our lease counts, etc are correct // Make sure our lease counts, etc are correct
$this->update($dst_id); $this->update($dst_id);
// Delete the old customer
$this->pr(12, compact('src_id'), "Delete Customer"); $this->pr(12, compact('src_id'), "Delete Customer");
$this->delete($src_id); $this->delete($src_id);
foreach (array_diff_key($all_contacts, array_flip($contacts)) AS $contact_id) { // Delete all the orphaned customers
foreach (array_diff(array_keys($src_contacts), $contacts) AS $contact_id) {
// Delete un-used or duplicate contacts // Delete un-used or duplicate contacts
// REVISIT <AP> 20100716: // REVISIT <AP> 20100702:
// Not sure if we really want to do this. // Not sure if we really want to do this.
// On the one hand, they're probably really redundant, // On the one hand, they're probably really redundant,
// and only clutter up the list of all contacts. On the // and only clutter up the list of all contacts. On the
// other hand, it destroys data, not only losing the // other hand, it destroys data, not only losing the
// history, but making it difficult to recover if the // history, but making it difficult to recover if the
// merge is a mistake. // merge is a mistake. Additionally, we need to do
// extra checking to ensure that the contact is not
// in use by some other customer.
// We need some sort of Contact.deleted field... // We need some sort of Contact.deleted field...
$this->pr(12, compact('contact_id'), "Delete Contact"); $this->pr(12, compact('contact_id'), "Delete Contact");
$this->Contact->delete($contact_id); $this->Contact->delete($contact_id);
} }
// Finally, delete all customer contact relationships
$this->ContactsCustomer->deleteAll
(array('customer_id' => $src_id), false);
// Return the result // Return the result
return $this->prReturn($ret); return $this->prReturn($ret);
} }

View File

@@ -20,40 +20,12 @@ Configure::write('debug', '0');
// pre-submit callback // pre-submit callback
function verifyRequest() { function verifyRequest() {
var pid; if (!$("#src-customer-id").val()) {
var rows; alert("Must select source customer");
if (!$("#dst-customer-id").val()) {
alert("Must select destination customer");
return false;
}
pid = $('#<?php echo "primary-contacts-jqGrid"; ?>').getGridParam('selrow');
if (!pid) {
alert("Must select a primary contact");
return false; return false;
} }
rows = $('#<?php echo "contacts-jqGrid"; ?>').getGridParam('selarrrow'); rows = $('#<?php echo "contacts-jqGrid"; ?>').getGridParam('selarrrow');
if (!rows.length) {
alert("Must select at least one contact");
return false;
}
var found = false;
for (var i=0; i < rows.length; ++i) {
if (pid == rows[i]) {
found = true;
break;
}
}
if (!found) {
alert("Primary contact is not a member of the selected contacts");
return false;
}
$('#<?php echo "primary-contact-id"; ?>').val(pid);
$('#<?php echo "contact-ids"; ?>').val(serialize(rows)); $('#<?php echo "contact-ids"; ?>').val(serialize(rows));
// return false to prevent the form from being submitted; // return false to prevent the form from being submitted;
@@ -61,21 +33,11 @@ function verifyRequest() {
return true; return true;
} }
// Reset the form
function resetForm() {
$('#payment-entry-id').val(1);
$('#payments').html('');
//updateContacts();
}
function updateContacts() { function updateContacts() {
$('#contacts-jqGrid').clearGridData(); $('#contacts-jqGrid').clearGridData();
var filter = new Array(); var filter = new Array();
//filter['ContactsCustomer.customer_id'] = <?php echo $src_id ?>; filter['ContactsCustomer.customer_id'] = $("#src-customer-id").val();
//filter['ContactsCustomer.customer_id'] = $("#dst-customer-id").val();
filter['ContactsCustomer.customer_id'] = new Array(<?php echo $src_id ?>, $("#dst-customer-id").val());
var dynamic_post = new Array(); var dynamic_post = new Array();
dynamic_post['filter'] = filter; dynamic_post['filter'] = filter;
@@ -84,26 +46,16 @@ function updateContacts() {
$('#contacts-jqGrid') $('#contacts-jqGrid')
.setGridParam({ page: 1 }) .setGridParam({ page: 1 })
.trigger("reloadGrid"); .trigger("reloadGrid");
$('#primary-contacts-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#primary-contacts-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
/* var gridstate = $('#contacts-jqGrid').getGridParam('gridstate'); */
/* var gridstate = $('#primary-contacts-jqGrid').getGridParam('gridstate'); */
/* if (gridstate == 'hidden') */
/* $('#contacts .HeaderButton').click(); */
} }
function onRowSelect(grid_id, customer_id) { function onRowSelect(grid_id, customer_id) {
//$('#output-debug').append("select: "+grid_id+"; "+customer_id+"<BR>\n"); //$('#output-debug').append("select: "+grid_id+"; "+customer_id+"<BR>\n");
// Set the item id that will be returned with the form // Set the item id that will be returned with the form
$("#dst-customer-id").val(customer_id); $("#src-customer-id").val(customer_id);
// Get the item name from the grid // Get the item name from the grid
$("#dst-customer-name").html($(grid_id).getCell(customer_id, "Customer-name")); $("#src-customer-name").html($(grid_id).getCell(customer_id, "Customer-name"));
updateContacts(); updateContacts();
@@ -118,7 +70,7 @@ function onGridState(grid_id, state) {
$(".customer-selection-valid").hide(); $(".customer-selection-valid").hide();
} }
else { else {
if ($("#dst-customer-id").val() > 0) { if ($("#src-customer-id").val() > 0) {
$(".customer-selection-invalid").hide(); $(".customer-selection-invalid").hide();
$(".customer-selection-valid").show(); $(".customer-selection-valid").show();
} else { } else {
@@ -128,10 +80,6 @@ function onGridState(grid_id, state) {
} }
} }
/* function onContactsGridLoadComplete() { */
/* var userdata = $('#contacts-jqGrid').getGridParam('userData'); */
/* } */
--></script> --></script>
<?php <?php
@@ -145,8 +93,8 @@ echo $form->create(null, array('id' => 'customer-merge-form',
'action' => 'mergeFinal')))."\n"; 'action' => 'mergeFinal')))."\n";
echo '<input type="hidden" id="src-customer-id" name="src-id" value="'.$src_id.'" />'."\n"; echo '<input type="hidden" id="src-customer-id" name="src-id" value="0" />'."\n";
echo '<input type="hidden" id="dst-customer-id" name="dst-id" value="0" />'."\n"; echo '<input type="hidden" id="dst-customer-id" name="dst-id" value="'.$dst_id.'" />'."\n";
echo $this->element('customers', array echo $this->element('customers', array
('config' => array ('config' => array
@@ -154,7 +102,6 @@ echo $this->element('customers', array
'grid_div_class' => 'text-below', 'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#customers-list .HeaderButton\').click();'. 'caption' => ('<A HREF="#" ONCLICK="$(\'#customers-list .HeaderButton\').click();'.
' return false;">Select Customer</A>'), ' return false;">Select Customer</A>'),
//'grid_setup' => array('hiddengrid' => isset($customer['id'])),
'grid_events' => array('onSelectRow' => 'grid_events' => array('onSelectRow' =>
array('ids' => array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'), 'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
@@ -162,7 +109,7 @@ echo $this->element('customers', array
array('gridstate' => array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'), 'onGridState("#"+$(this).attr("id"), gridstate)'),
), ),
//'action' => 'current', 'filter' => array('Customer.id !=' => $dst_id),
//'nolinks' => true, //'nolinks' => true,
'limit' => 10, 'limit' => 10,
))); )));
@@ -170,7 +117,7 @@ echo $this->element('customers', array
echo ('<DIV CLASS="customer-merge grid-selection-text">' . echo ('<DIV CLASS="customer-merge grid-selection-text">' .
'<DIV CLASS="customer-selection-valid" style="display:none">' . '<DIV CLASS="customer-selection-valid" style="display:none">' .
'Destination Customer: <SPAN id="dst-customer-name"></SPAN>' . 'Destination Customer: <SPAN id="src-customer-name"></SPAN>' .
'</DIV>' . '</DIV>' .
'<DIV CLASS="customer-selection-invalid" style="display:none">' . '<DIV CLASS="customer-selection-invalid" style="display:none">' .
@@ -179,42 +126,15 @@ echo ('<DIV CLASS="customer-merge grid-selection-text">' .
'</DIV>' . "\n"); '</DIV>' . "\n");
echo $this->element('contacts', array
(// Grid configuration
'config' => array
(
'grid_div_id' => 'primary-contacts',
/* 'grid_events' => array('onSelectRow' => */
/* array('ids' => */
/* 'if (ids != null){$("#primary-contacts-list .HeaderButton").click();}')), */
'grid_setup' => array('select' => true),
'caption' => 'Primary Contact',
'filter' => array('ContactsCustomer.customer_id' => $src_id),
//'exclude' => array('Customer', 'Type', 'Debit', 'Credit'),
//'include' => array('Applied', 'Balance'),
//'remap' => array('Received' => 'Paid'),
//'limit' => 20,
),
));
// Add a hidden item to hold the jqGrid selection,
// which we'll populate prior to form submission.
echo "\n";
echo '<input type="hidden" id="primary-contact-id" name="primary-contact-id" value="0" />'."\n";
echo $this->element('contacts', array echo $this->element('contacts', array
(// Grid configuration (// Grid configuration
'config' => array 'config' => array
( (
'grid_div_id' => 'contacts', 'grid_div_id' => 'contacts',
//'grid_events' => array('loadComplete' => 'onContactsGridLoadComplete()'),
'grid_setup' => array('multiselect' => true), 'grid_setup' => array('multiselect' => true),
'caption' => 'Combined Contacts', 'caption' => 'Source contacts to keep',
'filter' => array('ContactsCustomer.customer_id' => $src_id), 'filter' => array('ContactsCustomer.customer_id' => 0),
//'exclude' => array('Customer', 'Type', 'Debit', 'Credit'), 'include' => array('Relationship', 'License', 'Comment'),
//'include' => array('Applied', 'Balance'),
//'remap' => array('Received' => 'Paid'),
//'limit' => 20,
), ),
)); ));
@@ -226,7 +146,7 @@ echo '<input type="hidden" id="contact-ids" name="contact-ids" value="" />'."\n"
?> ?>
<H3>WARNING!</H3> <H3>WARNING!</H3>
<?php echo $src_name ?> is about to be deleted, and all data (leases, transactions, etc) from that customer will be merged into the destination customer selected above. This process is NOT reversible, so please ensure the selections are correct before proceeding.<BR> The above selected customer is about to be deleted, and all related data (leases, transactions, etc) will be merged into customer #<?php echo $dst_id ?>: <?php echo $dst_name ?>. This process is NOT reversible, so please ensure the selections are correct before proceeding.<BR>
<?php <?php
echo $form->end('Merge Customers') . "\n"; echo $form->end('Merge Customers') . "\n";
@@ -242,12 +162,10 @@ Configure::write('debug', '0');
<script type="text/javascript"><!-- <script type="text/javascript"><!--
$(document).ready(function(){ $(document).ready(function(){
$("#dst-customer-id").val(0); $("#src-customer-id").val(0);
$("#dst-customer-name").html("INTERNAL ERROR"); $("#src-customer-name").html("INTERNAL ERROR");
//onGridState(null, 'visible'); //onGridState(null, 'visible');
resetForm();
<?php if ($this->params['dev']): ?> <?php if ($this->params['dev']): ?>
$('#output-debug').show(); $('#output-debug').show();
<?php endif; ?> <?php endif; ?>

View File

@@ -6,6 +6,7 @@ $cols['Relationship'] = array('index' => 'ContactsCustomer.type', 'formatter'
$cols['Name'] = array('index' => 'Contact.display_name', 'formatter' => 'longname'); $cols['Name'] = array('index' => 'Contact.display_name', 'formatter' => 'longname');
$cols['Last Name'] = array('index' => 'Contact.last_name', 'formatter' => 'name'); $cols['Last Name'] = array('index' => 'Contact.last_name', 'formatter' => 'name');
$cols['First Name'] = array('index' => 'Contact.first_name', 'formatter' => 'name'); $cols['First Name'] = array('index' => 'Contact.first_name', 'formatter' => 'name');
$cols['License'] = array('index' => 'Contact.id_local', 'formatter' => 'name');
$cols['Company'] = array('index' => 'Contact.company_name', 'formatter' => 'longname'); $cols['Company'] = array('index' => 'Contact.company_name', 'formatter' => 'longname');
$cols['Comment'] = array('index' => 'Contact.comment', 'formatter' => 'comment'); $cols['Comment'] = array('index' => 'Contact.comment', 'formatter' => 'comment');
@@ -16,4 +17,4 @@ $grid
->defaultFields(array('Last Name', 'First Name')) ->defaultFields(array('Last Name', 'First Name'))
->searchFields(array('Last Name', 'First Name', 'Company')) ->searchFields(array('Last Name', 'First Name', 'Company'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Relationship', 'Comment'))); array_diff(array_keys($cols), array('Relationship', 'License', 'Comment')));