Commit 780f833f authored by jaapjansma's avatar jaapjansma
Browse files

added matcher for creating a new contact

parent d9da7aa0
<?php
/**
* @author Jaap Jansma <jaap.jansma@civicoop.org>
* @license AGPL-3.0
*/
use CRM_Barnekreftbanking_ExtensionUtil as E;
class CRM_Banking_PluginImpl_Matcher_BkfNewContact extends CRM_Banking_PluginModel_Matcher {
/**
* class constructor
*/
function __construct($config_name) {
parent::__construct($config_name);
// read config, set defaults
$config = $this->_plugin_config;
if (!isset($config->auto_exec)) $config->auto_exec = false;
if (!isset($config->threshold)) $config->threshold = 0.0;
if (!isset($config->skip_fields)) {
$config->skip_fields = [
'contribution_page_id',
'receive_date',
'non_deductible_amount',
'total_amount',
'fee_amount',
'net_amount',
'contribution_status_id',
'trxn_id',
'invoice_id',
'invoice_number',
'currency',
'cancel_date',
'cancel_reason',
'receipt_date',
'thankyou_date',
'amount_level',
'contribution_recur_id',
'is_test',
'is_pay_later',
'creditnote_id',
'tax_amount',
'revenue_recognition_date',
'id',
'contact_id',
'address_id',
'check_number',
'payment_processor',
'soft_credit_to',
'honor_contact_id',
'honor_type_id',
'skipRecentView',
'skipLineItem',
'batch_id',
'refund_trxn_id',
'card_type_id'
];
}
}
/**
* Returns whether the plugin is configured to execute unsupervised
*
* @return bool
*/
function autoExecute() {
return false;
}
public function match(CRM_Banking_BAO_BankTransaction $btx, CRM_Banking_Matcher_Context $context) {
$config = $this->_plugin_config;
$threshold = $this->getThreshold();
$penalty = $this->getPenalty($btx);
$data_parsed = $btx->getDataParsed();
$suggestion = new CRM_Banking_Matcher_Suggestion($this, $btx);
$suggestion->setTitle(E::ts("Create a new contact with a contribution"));
$probability = 1.0 - $penalty;
if ($probability >= $threshold) {
$suggestion->setProbability($probability);
$btx->addSuggestion($suggestion);
}
return empty($this->_suggestions) ? null : $this->_suggestions;
}
/**
* Generate html code to visualize the given match. The visualization may also provide interactive form elements.
*
* @val $match match data as previously generated by this plugin instance
* @val $btx the bank transaction the match refers to
* @return html code snippet
*/
function visualize_match( CRM_Banking_Matcher_Suggestion $match, $btx) {
$skipContributionFields = $this->_plugin_config->skip_fields;
$smarty_vars['data'] = $btx->getDataParsed();
$data_parsed = $btx->getDataParsed();
$fields = [
'contact.first_name' => ['label' => E::ts('First name'), 'required' => true, 'size' => 64],
'contact.last_name' => ['label' => E::ts('Last name'), 'required' => true, 'size' => 64],
'contact.street_address' => ['label' => E::ts('Street address'), 'required' => false, 'size' => 64],
'contact.postal_code' => ['label' => E::ts('Postal code'), 'required' => false, 'size' => 64],
'contact.city' => ['label' => E::ts('City'), 'required' => false, 'size' => 64],
];
$contributionFieldsApi = civicrm_api3('Contribution', 'getfields', ['api_action' => 'create']);
foreach($contributionFieldsApi['values'] as $contributionField) {
if (in_array($contributionField['name'], $skipContributionFields)) {
continue;
}
$fields['contribution.'.$contributionField['name']] = [
'label' => $contributionField['title'],
'required' => isset($contributionField['api.required']) ? $contributionField['api.required'] : false,
];
if (isset($contributionField['FKApiName'])) {
$fields['contribution.'.$contributionField['name']]['FKApiName'] = $contributionField['FKApiName'];
} elseif (isset($contributionField['pseudoconstant'])) {
$options = civicrm_api3('Contribution', 'getoptions', [
'field' => $contributionField['name'],
]);
$fields['contribution.'.$contributionField['name']]['options'] = $options['values'];
}
}
$smarty_vars['fields'] = $fields;
$contact_params = $match->getParameter('contact_params');
if (!is_array($contact_params)) {
$contact_params = [
'street_address' => isset($data_parsed['street_address']) ? $data_parsed['street_address'] : null,
'postal_code' => isset($data_parsed['postal_code']) ? $data_parsed['postal_code'] : null,
'city' => isset($data_parsed['city']) ? $data_parsed['city'] : null,
];
}
$contribution_params = $match->getParameter('contribution_params');
if (!is_array($contribution_params)) {
$contribution_params = [
'payment_instrument_id' => isset($data_parsed['payment_instrument_id']) ? $data_parsed['payment_instrument_id'] : null,
'financial_type_id' => 1, // Gave
'note' => isset($data_parsed['purpose']) ? $data_parsed['purpose'] : null,
];
}
$values = [];
foreach($contact_params as $k => $v) {
$values["contact.".$k] = $v;
}
foreach($contribution_params as $k => $v) {
$values["contribution.".$k] = $v;
}
$smarty_vars['values'] = $values;
// assign to smarty and compile HTML
$smarty = CRM_Core_Smarty::singleton();
$smarty->pushScope($smarty_vars);
$html_snippet = $smarty->fetch('CRM/Banking/PluginImpl/Matcher/BkfNewContact.suggestion.tpl');
$smarty->popScope();
return $html_snippet;
}
/**
* If the user has modified the input fields provided by the "visualize" html code,
* the new values will be passed here BEFORE execution
*
* CAUTION: there might be more parameters than provided. Only process the ones that
* 'belong' to your suggestion.
*/
public function update_parameters(CRM_Banking_Matcher_Suggestion $match, $parameters) {
$contact_params = [];
$contribution_params = [];
foreach($parameters as $key => $value) {
if (stripos($key, "contact_") === 0) {
$contact_params[substr($key, 8)] = $value;
} elseif (stripos($key, "contribution_") === 0) {
$contribution_params[substr($key, 13)] = $value;
}
}
$match->setParameter('contact_params', $contact_params);
$match->setParameter('contribution_params', $contribution_params);
}
/**
* Executes a previously generated match, i.e. the suggestion is accepted and realized
*
* Obviously, this method should be overwritten by the individual matchers,
* but DON'T forget to call parent::execute($match, $btx);
*
* @val $match match data as previously generated by this plugin instance
* @val $btx the bank transaction the match refers to
* @return the execution result: TRUE successfull
* NULL/FALSE if not successfull
* 're-run' if the analysis should be re-run (UI only)
*/
public function execute( $match, $btx ) {
$skipContributionFields = $this->_plugin_config->skip_fields;
$contact_params = $match->getParameter('contact_params');
$contribution_params = $match->getParameter('contribution_params');
if (empty($contact_params['first_name']) || empty($contact_params['last_name'])) {
return FALSE;
}
$contributionFieldsApi = civicrm_api3('Contribution', 'getfields', ['api_action' => 'create']);
foreach($contributionFieldsApi['values'] as $contributionField) {
if (!in_array($contributionField['name'], $skipContributionFields) && isset($contributionField['api.required']) && $contributionField['api.required'] && !isset($contribution_params[$contributionField['name']])) {
return FALSE;
}
}
$contact_params['contact_type'] = 'Individual';
$result = civicrm_api3('Contact', 'create', $contact_params);
$contact_id = $result['id'];
$contribution_params['contact_id'] = $contact_id;
$contribution_params['total_amount'] = $btx->amount;
$contribution_params['receive_date'] = $btx->value_date;
$contribution_params['currency'] = $btx->currency;
$contribution_params['contribution_status_id'] = 1; //Completed
$result = civicrm_api3('Contribution', 'create', $contribution_params);
$contribution_id = $result['id'];
$match->setParameter('contact_id', $contact_id);
$match->setParameter('contribution_id', $contribution_id);
// save the account
$this->storeAccountWithContact($btx, $match->getParameter('contact_id'));
// wrap it up
$newStatus = banking_helper_optionvalueid_by_groupname_and_name('civicrm_banking.bank_tx_status', 'Processed');
$btx->setStatus($newStatus);
parent::execute($match, $btx);
return TRUE;
}
/**
* Generate html code to visualize the executed match.
*
* @val $match match data as previously generated by this plugin instance
* @val $btx the bank transaction the match refers to
* @return html code snippet
*/
function visualize_execution_info( CRM_Banking_Matcher_Suggestion $match, $btx) {
// just assign to smarty and compile HTML
$smarty_vars = array();
$smarty_vars['contribution_id'] = $match->getParameter('contribution_id');
$smarty_vars['contact_id'] = $match->getParameter('contact_id');
$smarty_vars['display_name'] = civicrm_api('Contact', 'getvalue', array('id' => $smarty_vars['contact_id'], 'return' => 'display_name', 'version' => 3));
// assign to smarty and compile HTML
$smarty = CRM_Banking_Helpers_Smarty::singleton();
$smarty->pushScope($smarty_vars);
$html_snippet = $smarty->fetch('CRM/Banking/PluginImpl/Matcher/BkfNewContact.execution.tpl');
$smarty->popScope();
return $html_snippet;
}
}
......@@ -93,7 +93,7 @@ class CRM_Banking_PluginImpl_Matcher_CancelAvtaleGiro extends CRM_Banking_Plugin
$params[1] = $match->getParameter('mandate_reference');
$params[2] = CRM_Utils_System::url('civicrm/contact/view', array(
'reset' => 1,
'id' => $match->getParameter('contact_id'),
'cid' => $match->getParameter('contact_id'),
));
$params[3] = trim($match->getParameter('contact_name') . ' ['.$match->getParameter('contact_id').']');
......@@ -112,7 +112,7 @@ class CRM_Banking_PluginImpl_Matcher_CancelAvtaleGiro extends CRM_Banking_Plugin
$params[1] = $match->getParameter('mandate_reference');
$params[2] = CRM_Utils_System::url('civicrm/contact/view', array(
'reset' => 1,
'id' => $match->getParameter('contact_id'),
'cid' => $match->getParameter('contact_id'),
));
$params[3] = trim($match->getParameter('contact_name') . ' ['.$match->getParameter('contact_id').']');
......
......@@ -106,7 +106,7 @@ class CRM_Banking_PluginImpl_Matcher_ChangeNotification extends CRM_Banking_Plug
$params[1] = $match->getParameter('mandate_reference');
$params[2] = CRM_Utils_System::url('civicrm/contact/view', array(
'reset' => 1,
'id' => $match->getParameter('contact_id'),
'cid' => $match->getParameter('contact_id'),
));
$params[3] = trim($match->getParameter('contact_name') . ' ['.$match->getParameter('contact_id').']');
$params[4] = $match->getParameter('notification') ? E::ts('Yes') : E::ts('No');
......@@ -126,7 +126,7 @@ class CRM_Banking_PluginImpl_Matcher_ChangeNotification extends CRM_Banking_Plug
$params[1] = $match->getParameter('mandate_reference');
$params[2] = CRM_Utils_System::url('civicrm/contact/view', array(
'reset' => 1,
'id' => $match->getParameter('contact_id'),
'cid' => $match->getParameter('contact_id'),
));
$params[3] = trim($match->getParameter('contact_name') . ' ['.$match->getParameter('contact_id').']');
$params[4] = $match->getParameter('notification') ? E::ts('Yes') : E::ts('No');
......
......@@ -61,6 +61,23 @@ class CRM_Barnekreftbanking_Upgrader extends CRM_Barnekreftbanking_Upgrader_Base
));
}
try {
civicrm_api3('OptionValue', 'getvalue', array(
'return' => "id",
'option_group_id' => "civicrm_banking.plugin_types",
'name' => "matcher_new_contact",
));
} catch (Exception $e) {
// doesn't exist yet
civicrm_api3('OptionValue', 'create', array(
'option_group_id' => "civicrm_banking.plugin_types",
'name' => 'matcher_new_contact',
'label' => E::ts('New contact and contribution'),
'value' => 'CRM_Banking_PluginImpl_Matcher_BkfNewContact',
'is_default' => 0
));
}
try {
civicrm_api3('OptionValue', 'getvalue', array(
'return' => "id",
......@@ -161,6 +178,28 @@ class CRM_Barnekreftbanking_Upgrader extends CRM_Barnekreftbanking_Upgrader_Base
// Do nothing
}
try {
$matcher_plugin_class = civicrm_api3('OptionValue', 'getsingle', array('version' => 3, 'name' => 'matcher', 'group_id' => 'civicrm_banking.plugin_class'));
$matcher_id = civicrm_api3('OptionValue', 'getvalue', array(
'return' => "id",
'option_group_id' => "civicrm_banking.plugin_types",
'name' => "matcher_new_contact",
));
// Plugin type and plugin class are switched around
// see issue #29 (https://github.com/Project60/org.project60.banking/issues/29).
$params['plugin_type_id'] = $matcher_plugin_class['id'];
$params['plugin_class_id'] = $matcher_id;
$matcherPluginInstances = civicrm_api3('BankingPluginInstance', 'get', $params);
foreach($matcherPluginInstances['values'] as $matcherPluginInstance) {
civicrm_api3('BankingPluginInstance', 'delete', array('id' => $matcherPluginInstance['id']));
}
civicrm_api3('OptionValue', 'delete', array('id' => $matcher_id));
} catch (Exception $e) {
// Do nothing
}
try {
$import_plugin_class = civicrm_api3('OptionValue', 'getsingle', array('version' => 3, 'name' => 'postprocessor', 'group_id' => 'civicrm_banking.plugin_class'));
$importer_id = civicrm_api3('OptionValue', 'getvalue', array(
......@@ -222,4 +261,24 @@ class CRM_Barnekreftbanking_Upgrader extends CRM_Barnekreftbanking_Upgrader_Base
return true;
}
public function upgrade_1002() {
try {
civicrm_api3('OptionValue', 'getvalue', array(
'return' => "id",
'option_group_id' => "civicrm_banking.plugin_types",
'name' => "matcher_new_contact",
));
} catch (Exception $e) {
// doesn't exist yet
civicrm_api3('OptionValue', 'create', array(
'option_group_id' => "civicrm_banking.plugin_types",
'name' => 'matcher_new_contact',
'label' => E::ts('New contact and contribution'),
'value' => 'CRM_Banking_PluginImpl_Matcher_BkfNewContact',
'is_default' => 0
));
}
return TRUE;
}
}
......@@ -14,7 +14,7 @@
<url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
</urls>
<releaseDate>2020-02-25</releaseDate>
<version>1.3</version>
<version>1.4-dev</version>
<develStage>stable</develStage>
<compatibility>
<ver>5.13</ver>
......
{*-------------------------------------------------------+
| Project 60 - CiviBanking |
| Copyright (C) 2013-2018 SYSTOPIA |
| Author: B. Endres (endres -at- systopia.de) |
| http://www.systopia.de/ |
+--------------------------------------------------------+
| This program is released as free software under the |
| Affero GPL v3 license. You can redistribute it and/or |
| modify it under the terms of this license which you |
| can read by viewing the included agpl.txt or online |
| at www.gnu.org/licenses/agpl.html. Removal of this |
| copyright header is strictly prohibited without |
| written permission from the original author(s). |
+--------------------------------------------------------*}
{capture assign=contribution_link}{crmURL p="civicrm/contact/view/contribution" q="reset=1&id=$contribution_id&cid=$contact_id&action=view"}{/capture}
{capture assign=contact_link}{crmURL p="civicrm/contact/view" q="reset=1&cid=$contact_id"}{/capture}
<p>
{ts 1=$contact_link 2=$display_name 3=$contribution_link 4=$contribution_id domain='org.project60.banking'}This transaction created a new contact <a href="%1">%2</a> and was associated with the new <a href="%3">contribution #%4</a>.{/ts}
</p>
{crmScope extensionKey='barnekreftbanking'}
<div class="crm-block crm-form-block">
{foreach from=$fields item=field key=field_name}
<div class="crm-section">
<div class="label">
<label for="{$field_name}">
{$field.label}
{if $field.required}<span class="crm-marker" title="This field is required.">*</span>{/if}
</label>
</div>
<div class="content">
{if (isset($field.FKApiName))}
<input
placeholder="{$field.label}"
type="text" name="{$field_name}"
class="crm-form-text huge
{if $field.required}required{/if}" {if $field.required}required="required"{/if}
data-api-entity="{$field.FKApiName}"
data-select-params='{literal}{{/literal}"minimumInputLength":0{literal}}{/literal}'
{if (isset($values.$field_name))}value="{$values.$field_name}"{/if}
/>
{elseif isset($field.options)}
<select placeholder="{$field.label}" name="{$field_name}" value="" class="crm-form-select huge {if $field.required}required{/if}" {if $field.required}required="required"{/if}>
<option value="">{ts}- Select -{/ts}</option>
{foreach from=$field.options item=option_label key=option_value}
<option value="{$option_value}" {if (isset($values.$field_name) && $values.$field_name == $option_value)}selected="selected"{/if}>{$option_label}</option>
{/foreach}
</select>
{else}
<input
type="text"
size="{$field.html_size}"
name="{$field_name}"
class="crm-form-text huge
{if $field.required}required{/if}" {if $field.required}required="required"{/if}
{if (isset($values.$field_name))}value="{$values.$field_name}"{/if}
/>
{/if}
</div>
<div class="clear"></div>
</div>
{/foreach}
</div>
{literal}
<script type="text/javascript">
CRM.$(function($) {
{/literal}
{foreach from=$fields item=field key=field_name}
{if (isset($field.FKApiName))}
$('[name="{$field_name}"]').crmEntityRef();
{/if}
{/foreach}
{literal}
});
</script>
{/literal}
{/crmScope}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment