Commit 1bd98e42 authored by Michael Iseard's avatar Michael Iseard
Browse files

Initial work on checking if Mollie account can receive recurring payments

parent d2823a54
......@@ -255,7 +255,7 @@ class Settings {
'amount_type' => 'both',
'fixed_amounts' => '1,5,20,50',
'campaign_goal' => '',
'donation_type' => 'both',
'donation_type' => 'oneoff',
'protected' => true,
],
],
......
......@@ -116,7 +116,7 @@ class ActivatorService {
}
if ( version_compare( $old_version, '2.3.8', '<' ) ) {
if ( version_compare( $old_version, '2.3.9', '<' ) ) {
// Setting now replaced by single 'vendor_mollie' setting
if(Settings::update_setting( 'vendor_mollie', [
......
......@@ -325,10 +325,11 @@ class PaymentService extends AbstractService {
*/
public function check_api_keys( WP_REST_Request $request ) {
Settings::update_array( 'vendor_mollie', [
'connected' => false,
'recurring' => false
] );
Settings::update_array( 'vendor_mollie',
[
'connected' => false,
'recurring' => false,
] );
$mode = sanitize_text_field( $request['apiMode'] );
$api_key = sanitize_text_field( $request[ $mode . 'Key' ] );
......@@ -342,25 +343,32 @@ class PaymentService extends AbstractService {
}
// Test the api key.
$result = $this->vendor->test_api_connection( $api_key );
$result = $this->vendor->refresh_api_connection( $api_key );
if ( $result ) {
Settings::update_array( 'vendor_mollie', [
'mode' => $mode,
$mode . '_key' => $api_key,
'connected' => 1,
'recurring' => $this->vendor->get_payment_methods()->count > 0 ?? 0
] );
Settings::update_array( 'vendor_mollie',
[
'mode' => $mode,
$mode . '_key' => $api_key,
'connected' => 1,
'recurring' => $this->vendor->get_payment_methods()->count > 0 ?? 0,
] );
wp_send_json_success(
/* translators: %s: API mode */
sprintf( __( '%s API key connection was successful!', 'kudos-donations' ), ucfirst( $mode ) )
[
/* translators: %s: API mode */
'message' => sprintf( __( '%s API key connection was successful!', 'kudos-donations' ),
ucfirst( $mode ) ),
'setting' => Settings::get_setting( 'vendor_mollie' ),
]
);
} else {
wp_send_json_error(
/* translators: %s: API mode */
sprintf( __( 'Error connecting with Mollie, please check the %s API key and try again.',
'kudos-donations' ),
ucfirst( $mode ) )
[
/* translators: %s: API mode */
'message' => sprintf( __( 'Error connecting with Mollie, please check the %s API key and try again.',
'kudos-donations' ),
ucfirst( $mode ) ),
]
);
}
}
......
......@@ -49,7 +49,7 @@ abstract class AbstractVendor extends AbstractService {
* @return bool
* @since 1.0.0
*/
abstract public function test_api_connection( string $api_key ): bool;
abstract public function refresh_api_connection( string $api_key ): bool;
/**
* Gets specified payment
......
......@@ -57,10 +57,10 @@ class MollieVendor extends AbstractVendor {
$this->mollie_api = new MollieApiClient();
$settings = Settings::get_setting('vendor_mollie');
$settings = Settings::get_setting( 'vendor_mollie' );
$this->api_mode = $settings['mode'];
$this->api_key = isset($settings[ $this->api_mode . '_key' ]) ? $settings[ $this->api_mode . '_key' ] : '';
$this->api_mode = $settings['mode'];
$this->api_key = isset( $settings[ $this->api_mode . '_key' ] ) ? $settings[ $this->api_mode . '_key' ] : '';
if ( $this->api_key ) {
try {
......@@ -109,7 +109,7 @@ class MollieVendor extends AbstractVendor {
$mapper = new MapperService( SubscriptionEntity::class );
/** @var SubscriptionEntity $subscription */
$subscription = $mapper->get_one_by( [ 'subscription_id' => $subscription_id ] );
$customer_id = $subscription->customer_id;
$customer_id = $subscription->customer_id;
$customer = $this->get_customer( $customer_id );
......@@ -128,6 +128,7 @@ class MollieVendor extends AbstractVendor {
} catch ( ApiException $e ) {
$this->logger->critical( $e->getMessage() );
return false;
}
......@@ -141,7 +142,7 @@ class MollieVendor extends AbstractVendor {
* @return bool
* @since 1.0.0
*/
public function test_api_connection( string $api_key ): bool {
public function refresh_api_connection( string $api_key ): bool {
if ( ! $api_key ) {
return false;
......@@ -370,15 +371,15 @@ class MollieVendor extends AbstractVendor {
*
* @return BaseCollection|MethodCollection|null
*/
public function get_payment_methods($sequenceType='recurring') {
public function get_payment_methods( $sequenceType = 'recurring' ) {
try {
return $this->mollie_api->methods->allActive([
return $this->mollie_api->methods->allActive( [
'sequenceType' => $sequenceType,
]);
] );
} catch (ApiException $e) {
} catch ( ApiException $e ) {
$this->logger->critical( $e->getMessage(), [ 'payment' => $payment_array ] );
return null;
......
......@@ -69,12 +69,22 @@ const ButtonIcon = (props) => {
d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"/>
</svg>
)
case 'sync':
return (
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512">
<path fill="currentColor"
d="M440.65 12.57l4 82.77A247.16 247.16 0 0 0 255.83 8C134.73 8 33.91 94.92 12.29 209.82A12 12 0 0 0 24.09 224h49.05a12 12 0 0 0 11.67-9.26 175.91 175.91 0 0 1 317-56.94l-101.46-4.86a12 12 0 0 0-12.57 12v47.41a12 12 0 0 0 12 12H500a12 12 0 0 0 12-12V12a12 12 0 0 0-12-12h-47.37a12 12 0 0 0-11.98 12.57zM255.83 432a175.61 175.61 0 0 1-146-77.8l101.8 4.87a12 12 0 0 0 12.57-12v-47.4a12 12 0 0 0-12-12H12a12 12 0 0 0-12 12V500a12 12 0 0 0 12 12h47.35a12 12 0 0 0 12-12.6l-4.15-82.57A247.17 247.17 0 0 0 255.83 504c121.11 0 221.93-86.92 243.55-201.82a12 12 0 0 0-11.8-14.18h-49.05a12 12 0 0 0-11.67 9.26A175.86 175.86 0 0 1 255.83 432z"/>
</svg>
)
}
}
return (
<Icon
size="16"
className={props.className}
icon={icon()}
/>
)
......
const {Dashicon} = wp.components
const Info = (props) => {
const Info = ({level="info", children}) => {
let text = 'kd-text-gray-500'
let icon = 'info'
switch (level) {
case "warning":
text = 'kd-text-orange-700'
icon = 'warning'
break;
}
return (
<div className="kudos-admin-info kd-text-gray-500 kd-flex kd-items-center kd-justify-start">
<Dashicon className="kd-mr-1" icon={props.icon ?? "info"}/>
<i>{props.children}</i>
<div className={"kd-flex kd-items-center kd-justify-start " + text}>
<Dashicon className="kd-mr-1" icon={icon}/>
<i>{children}</i>
</div>
)
......
......@@ -10,6 +10,7 @@ const {
CardFooter,
CheckboxControl,
ClipboardButton,
Disabled,
RadioControl,
TextControl,
ToggleControl
......@@ -23,6 +24,21 @@ const CampaignPanel = ({settings, campaign, removeCampaign, handleInputChange, a
setHasCopied(false)
}, [campaign])
let donation_type = <RadioControl
selected={campaign.donation_type || 'both'}
disabled={settings._kudos_vendor_mollie.recurring ? null : true}
help={__('The donation type of the form, set to "both" to allow donor to choose.', 'kudos-donations')}
options={[
{label: __('One-off', 'kudos-donations'), value: 'oneoff'},
{label: __('Subscription', 'kudos-donations'), value: 'recurring'},
{label: __('Both', 'kudos-donations'), value: 'both'},
]}
onChange={(value) => {
campaign.donation_type = value
handleInputChange('_kudos_campaigns', settings._kudos_campaigns)
}}
/>
return (
<div id={"campaign-" + campaign.id}>
<SettingCard title={__('General', 'kudos-donations')} id="campaignPanel" settings={settings} campaign={campaign} handleInputChange={handleInputChange}>
......@@ -111,19 +127,14 @@ const CampaignPanel = ({settings, campaign, removeCampaign, handleInputChange, a
<SettingCard title={__('Donation type', 'kudos-donations')}>
<RadioControl
selected={campaign.donation_type || 'both'}
help={__('The donation type of the form, set to "both" to allow donor to choose.', 'kudos-donations')}
options={[
{label: __('One-off', 'kudos-donations'), value: 'oneoff'},
{label: __('Subscription', 'kudos-donations'), value: 'recurring'},
{label: __('Both', 'kudos-donations'), value: 'both'},
]}
onChange={(value) => {
campaign.donation_type = value
handleInputChange('_kudos_campaigns', settings._kudos_campaigns)
}}
/>
{(!settings._kudos_vendor_mollie.recurring) ?
<Disabled>
{donation_type}
<Info level="warning">
{__('You need to enable SEPA Direct Debit or Credit card in your Mollie account to use supscription payments', 'kudos-donations')}
</Info>
</Disabled>
: donation_type }
</SettingCard>
......
import {Btn} from "../Btn"
import {SettingCard} from "../SettingCard"
import {ButtonIcon} from "../ButtonIcon"
const {__} = wp.i18n
const {BaseControl, ButtonGroup, PanelRow} = wp.components
const {BaseControl, Button, ButtonGroup, PanelRow} = wp.components
const {useState} = wp.element
const MollieApiModePanel = (props) => {
const [isBusy, setIsBusy] = useState(false)
const vendorMollie = props.settings._kudos_vendor_mollie
const selected = vendorMollie['mode']
const handleChange = (id, value) => {
props.mollieChanged()
props.handleInputChange(id, value)
}
const vendorMollie = props.settings._kudos_vendor_mollie
const selected = vendorMollie['mode']
const refresh = () => {
setIsBusy(true)
props.checkApiKey(() => setIsBusy(false))
}
return (
<SettingCard title={__('API mode', 'kudos-donations')}>
......@@ -53,6 +62,18 @@ const MollieApiModePanel = (props) => {
</PanelRow>
</BaseControl>
<BaseControl
help={__("Use this if you have made changes in Mollie such as enabling SEPA Direct Debit or Credit Card.", 'kudos-donations')}
>
<Button
isLink
icon={(<ButtonIcon icon='sync' className={(isBusy ? 'kd-animate-spin' : '')}/>)}
onClick={() => refresh()}
>
{__('Refresh API', 'kudos-donations')}
</Button>
</BaseControl>
</SettingCard>
)
}
......
......@@ -10,6 +10,7 @@ const MollieTab = (props) => {
<MollieApiModePanel
settings={props.settings}
mollieChanged={props.mollieChanged}
checkApiKey={props.checkApiKey}
handleInputChange={props.handleInputChange}
/>
<CardDivider/>
......
......@@ -66,12 +66,6 @@ class KudosAdmin extends Component {
mollieChanged() {
this.setState({
isMollieEdited: true,
settings: {
_kudos_vendor_mollie: {
...this.state.settings._kudos_vendor_mollie,
connected: false
}
},
})
}
......@@ -79,7 +73,8 @@ class KudosAdmin extends Component {
updateQueryParameter('tab_name', tab)
}
checkApiKey() {
checkApiKey(callback) {
this.setState({
checkingApi: true,
isAPISaving: true,
......@@ -99,17 +94,24 @@ class KudosAdmin extends Component {
},
})
.then((response) => {
this.showNotice(response.data.data)
this.showNotice(response.data.data.message)
this.setState({
settings: {
_kudos_vendor_mollie: {
...this.state.settings._kudos_vendor_mollie,
connected: response.data.success
}
},
checkingApi: false,
isAPISaving: false,
})
if(response.data.success) {
this.setState({
settings: {
...this.state.settings,
_kudos_vendor_mollie: {
...response.data.data.setting
}
}
})
}
if(typeof callback === "function") {
callback()
}
})
}
......@@ -249,6 +251,8 @@ class KudosAdmin extends Component {
<MollieTab
settings={this.state.settings}
mollieChanged={this.mollieChanged}
showNotice={this.showNotice}
checkApiKey={this.checkApiKey}
handleInputChange={this.handleInputChange}
/>
},
......
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