Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Reimbursement flow to wpaustralia for ease of use and sanity #20

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions wp-content/plugins/wpaus-reimbursements/flamingo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
<?php
namespace WPAustralia\Reimbursements\Flamingo;

// Linkify links in flamingo lists.
add_filter( 'flamingo_htmlize', 'make_clickable' );

/**
* Add custom Statuses.
*/
function register_post_statuses() {
register_post_status( 'paid', array(
'post_type' => \Flamingo_Inbound_Message::post_type,
'label' => 'Paid',
'public' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
) );

register_post_status( 'approved', array(
'post_type' => \Flamingo_Inbound_Message::post_type,
'label' => 'Approved',
'public' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
) );

register_post_status( 'declined', array(
'post_type' => \Flamingo_Inbound_Message::post_type,
'label' => 'Declined',
'public' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
) );
}
add_action( 'flamingo_init', __NAMESPACE__ . '\register_post_statuses');

/**
* Add the Approved/Declined/Paid statuses to the table filter.
*/
add_filter( 'views_flamingo_page_flamingo_inbound', function( $views ) {

// Overide the Inbox item to override the current class.
$count = \Flamingo_Inbound_Message::count([ 'post_status' => 'publish' ]);
$text = sprintf(
_nx(
'Inbox <span class="count">(%s)</span>',
'Inbox <span class="count">(%s)</span>',
$count, 'posts', 'wpaus'
),
number_format_i18n( $count )
);
$views['inbox'] = sprintf(
'<a href="%1$s"%2$s>%3$s</a>',
menu_page_url( 'flamingo_inbound', false ),
( ! isset( $_REQUEST['post_status'] ) ) ? ' class="current"' : '',
$text
);

$count = \Flamingo_Inbound_Message::count([ 'post_status' => 'approved' ]);
$text = sprintf(
_nx(
'Approved <span class="count">(%s)</span>',
'Approved <span class="count">(%s)</span>',
$count, 'posts', 'wpaus'
),
number_format_i18n( $count )
);
$views['approved'] = sprintf(
'<a href="%1$s"%2$s>%3$s</a>',
add_query_arg( ['post_status' => 'approved'], menu_page_url( 'flamingo_inbound', false ) ),
( isset( $_REQUEST['post_status'] ) && 'approved' === $_REQUEST['post_status'] ) ? ' class="current"' : '',
$text
);

$count = \Flamingo_Inbound_Message::count([ 'post_status' => 'paid' ]);
$text = sprintf(
_nx(
'Paid <span class="count">(%s)</span>',
'Paid <span class="count">(%s)</span>',
$count, 'posts', 'wpaus'
),
number_format_i18n( $count )
);
$views['paid'] = sprintf(
'<a href="%1$s"%2$s>%3$s</a>',
add_query_arg( ['post_status' => 'paid'], menu_page_url( 'flamingo_inbound', false ) ),
( isset( $_REQUEST['post_status'] ) && 'paid' === $_REQUEST['post_status'] ) ? ' class="current"' : '',
$text
);

$count = \Flamingo_Inbound_Message::count([ 'post_status' => 'declined' ]);
$text = sprintf(
_nx(
'Declined <span class="count">(%s)</span>',
'Declined <span class="count">(%s)</span>',
$count, 'posts', 'wpaus'
),
number_format_i18n( $count )
);
$views['declined'] = sprintf(
'<a href="%1$s"%2$s>%3$s</a>',
add_query_arg( ['post_status' => 'declined'], menu_page_url( 'flamingo_inbound', false ) ),
( isset( $_REQUEST['post_status'] ) && 'declined' === $_REQUEST['post_status'] ) ? ' class="current"' : '',
$text
);

return $views;
});

/**
* Allow filtering to approved/declined/paid
*/
add_filter( 'pre_get_posts', function( $query ) {
if (
is_admin() &&
isset( $_GET['page'] ) && 'flamingo_inbound' === $_GET['page'] &&
( empty( $query->query['post_status'] ) || 'any' === $query->query['post_status'] )
) {
if ( \Flamingo_Inbound_Message::post_type === $query->query['post_type'] ) {
$query->query['post_status'] = $query->query_vars['post_status'] = $_REQUEST['post_status'] ?? 'publish';
}
}
});

/**
* Save additional approved/declined/paid statuses.
*/
add_action( 'load-flamingo_page_flamingo_inbound', function() {
if (
'save' == flamingo_current_action() &&
! empty( $_REQUEST['post'] ) &&
! empty( $_POST['inbound']['status'] )
) {
$post = get_post( $_REQUEST['post'] );

if ( ! $post )
return;

if ( ! current_user_can( 'flamingo_edit_inbound_message', $post->ID ) )
wp_die( __( 'You are not allowed to edit this item.', 'flamingo' ) );

check_admin_referer( 'flamingo-update-inbound_' . $post->ID );

$status = $_POST['inbound']['status'];

if ( $status != get_post_status( $post->ID ) ) {
wp_update_post([
'ID' => $post->ID,
'post_status' => $status
]);
}
}
}, 9 );

/**
* Add the extra statuses to the Submit box.
*/
add_action( 'load-flamingo_page_flamingo_inbound', function() {
if ( 'edit' == flamingo_current_action() ) {
add_meta_box(
'submitdiv', __( 'Status', 'flamingo' ),
function( $post ) {
ob_start();
\flamingo_inbound_submit_meta_box( $post );
$output = ob_get_clean();

$statuses = [];
$status = get_post_status( $post->id );
if ( 'publish' === $status ) {
$status = 'ham';
}

// The statuses we need.
foreach ( [
'ham' => 'Inbox',
'approved' => 'Approved',
'declined' => 'Declined',
'paid' => 'Paid',
'spam' => 'Spam'
] as $value => $text ) {
$statuses[] = '<label><input type="radio" ' . checked( $status, $value, false ) . ' name="inbound[status]" value="' . $value . '">' . $text . '</label>';
}

echo preg_replace(
'!(<fieldset.+?>).+(</fieldset>)!is',
'$1' . implode( '<br>', $statuses ) . '$2',
$output
);
},
null, 'side', 'core'
);
}
});
14 changes: 14 additions & 0 deletions wp-content/plugins/wpaus-reimbursements/plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
namespace WPAustralia\Reimbursements;
/**
* Plugin Name: WP Australia Reimbursements
* Description: Expands upon Contact Form 7 & Flamingo to add reimbursement flow/etc.
*/

if ( ! class_exists( 'WPCF7_Submission' ) ) return;
if ( ! defined( 'FLAMINGO_VERSION' ) ) return;

include __DIR__ . '/wpcf7.php'; // For contact form integrations.
include __DIR__ . '/flamingo.php'; // For admin integration.
include __DIR__ . '/xero.php'; // For Xero integration.
include __DIR__ . '/public-shortcode.php'; // To provide a public log of approved/paid reimbursement transactions
79 changes: 79 additions & 0 deletions wp-content/plugins/wpaus-reimbursements/public-shortcode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
namespace WPAustralia\Reimbursements\PublicShortcode;

function reimbursement_listing_shortcode() {
ob_start();

$items = get_items();
echo '<ol>';
foreach ( $items as $item ) {
printf(
"<li>On <em>%s</em> <em>%s</em> requested <strong>$%s</strong> for the <em>%s</em> meetup held on <em>%s</em> for <em>%s</em> - <strong>%s</strong></li>",
gmdate( 'j F Y', strtotime( $item->when ) ),
$item->who,
number_format_i18n( $item->cost, 2 ),
$item->for[0],
gmdate( 'j F Y', strtotime( $item->for[1] ) ),
implode( ', ', array_map( function( $text ) {
// Remove any account prefixes, ie. 'FOOD - ', we only want descriptions.
return preg_replace( '!^[A-Z-]+ - (.+)$!', '$1', $text );
}, $item->what ) ),
ucwords( $item->status )
);
}
echo '</ol>';

return ob_get_clean();
}
add_shortcode( 'reimbursement-lisitng', __NAMESPACE__ . '\reimbursement_listing_shortcode' );

function get_items() {
// TODO: Should somehow get sponsor invoices into this set of data?

$items = [];
$messages = \Flamingo_Inbound_Message::find([
'posts_per_page' => 999,
'channel' => 'reimbursement-request',
'post_status' => [ 'publish', 'approved', 'declined', 'paid' ],
]);

foreach ( $messages as $m ) {
$status = 'Pending Review';
switch ( get_post_status( $m->id ) ) {
case 'publish':
$status = 'Pending Review';
break;
case 'approved':
$status = 'Pending Reimbursement';
break;
case 'declined':
case 'paid':
$status = ucwords( get_post_status( $m->id ) );
break;
}

$items[] = (object) [
'who' => $m->fields['your-name'],
'when' => get_post_field( 'post_date', $m->id ),
'for' => [ $m->fields['meetup'], $m->fields['date'] ],
'what' => array_unique( array_filter( [
$m->fields['category-one'],
$m->fields['category-two'] ?? false,
$m->fields['category-three'] ?? false,
$m->fields['category-four'] ?? false,
$m->fields['category-five'] ?? false,
] ) ),
'cost' => array_sum( [
$m->fields['cost-one'],
$m->fields['cost-two'] ?? 0.00,
$m->fields['cost-three'] ?? 0.00,
$m->fields['cost-four'] ?? 0.00,
$m->fields['cost-five'] ?? 0.00,
] ),
'status' => $status,
];

}

return $items;
}
91 changes: 91 additions & 0 deletions wp-content/plugins/wpaus-reimbursements/wpcf7.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
namespace WPAustralia\Reimbursements\CF7;

/**
* Filter out the extra file fields when not in use.
*/
function wpcf7_posted_data( $data ) {
foreach ( [ '-one', '-two', '-three', '-four', '-five' ] as $field_suffix ) {
$matching_fields = [];
foreach ( $data as $field => $field_data ) {
if ( substr( $field, -1*strlen( $field_suffix ) ) === $field_suffix ) {
$matching_fields[ $field ] = $field_data;
}
}

// If all are empty. unset.
$empty = array_filter( $matching_fields, function( $item ) {
return !empty( $item ) && $item !== '0.00';
} );
if ( ! $empty ) {
foreach ( array_keys( $matching_fields ) as $k ) {
unset( $data[ $k ] );
}
}
}

return $data;
}
add_filter( 'wpcf7_posted_data', __NAMESPACE__ . '\wpcf7_posted_data' );

/**
* CF7 deletes the files shortly after this action..
* Store them for later use.
*/
function wpcf7_mail_sent( $contact_form ) {
// "Copy" any uploaded files to tmp
$uploaded_files = \WPCF7_Submission::get_instance()->uploaded_files();

// ie. Put it back in $_FILES after move_uploaded_file() stole it.
foreach ( $uploaded_files as $form_field => $file ) {
$tmp_file = tempnam( sys_get_temp_dir(), 'reimbursement-' );

if ( copy( $file, $tmp_file ) ) {
$_FILES[ $form_field ]['tmp_name'] = $tmp_file;
}
}
}
add_action( 'wpcf7_mail_sent', __NAMESPACE__ . '\wpcf7_mail_sent' );


/**
* Attach files to the Flamingo message.
*/
function wpcf7_after_flamingo( $result ) {
if ( empty( $result['flamingo_inbound_id'] ) ) {
return;
}

$stored_message = new \Flamingo_Inbound_Message( $result['flamingo_inbound_id'] );
$uploaded_files = \WPCF7_Submission::get_instance()->uploaded_files();

if ( $uploaded_files ) {
$upload_dir = wp_upload_dir();
$reimbursements_dir = $upload_dir['basedir'] . '/reimbursements';
$reimbursements_url = $upload_dir['baseurl'] . '/reimbursements';

wp_mkdir_p( $reimbursements_dir );
if ( ! file_exists( "{$reimbursements_dir}/index.html" ) ) {
@touch( "{$reimbursements_dir}/index.html" );
}

foreach ( $uploaded_files as $form_field => $file ) {
$name = sprintf( "%s-%s-%s",
gmdate( 'Ymd' ),
wp_generate_password( 8, false ),
wp_basename( $file )
);
$name = wp_unique_filename( $reimbursements_dir, $name );

if ( rename( $_FILES[ $form_field ]['tmp_name'], "{$reimbursements_dir}/{$name}" ) ) {
@chmod( "{$reimbursements_dir}/{$name}", 0666 );

$stored_message->fields[ $form_field ] = "{$reimbursements_url}/{$name}";
}
}

$stored_message->save();
}

}
add_action( 'wpcf7_after_flamingo', __NAMESPACE__ . '\wpcf7_after_flamingo' );
Loading