<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[7291] sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments: WordCamp Payments: Add exporters for Vendor Payments and Reimbursement Requests.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/7291">7291</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/7291","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>vedjain</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2018-06-11 18:37:24 +0000 (Mon, 11 Jun 2018)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>WordCamp Payments: Add exporters for Vendor Payments and Reimbursement Requests.

This adds vendor payments (matches email of the vendor) and reimbursement request (matches email of the requester) data to the Personal Data exporter tool. Data will be exported for all post types, even when they are in draft.
Support for sponsor invoices is already included in `wc_post_types` plugin.

props vedanshu</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcamppaymentsbootstrapphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/bootstrap.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcamppaymentsincludesprivacyphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/includes/privacy.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcamppaymentsbootstrapphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/bootstrap.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/bootstrap.php   2018-06-09 04:41:44 UTC (rev 7290)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/bootstrap.php     2018-06-11 18:37:24 UTC (rev 7291)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -23,3 +23,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $GLOBALS['wordcamp_budgets']    = new WordCamp_Budgets();
</span><span class="cx" style="display: block; padding: 0 10px">        $GLOBALS['wcp_payment_request'] = new WCP_Payment_Request();
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+if ( is_admin() || wp_doing_cron() || wp_doing_ajax() ) {
+       require_once( __DIR__ . '/includes/privacy.php' );
+}
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcamppaymentsincludesprivacyphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/includes/privacy.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/includes/privacy.php                            (rev 0)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments/includes/privacy.php      2018-06-11 18:37:24 UTC (rev 7291)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,318 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace WordCamp\Budgets\Privacy;
+
+use WP_Query;
+use WordCamp\Budgets\Reimbursement_Requests;
+
+defined( 'WPINC' ) || die();
+
+
+add_filter( 'wp_privacy_personal_data_exporters', __NAMESPACE__ . '\register_personal_data_exporters' );
+add_filter( 'wp_privacy_personal_data_erasers', __NAMESPACE__ . '\register_personal_data_erasers' );
+
+/**
+ * Registers the personal data eraser for each WordCamp post type
+ *
+ * @param array $erasers
+ *
+ * @return array
+ */
+function register_personal_data_erasers( $erasers ) {
+       /**
+        * This is an empty stub, we are not adding an eraser for now, because it contains data which can be used for
+        * accounting or reference purpose.
+        *
+        */
+       return $erasers;
+}
+
+/**
+ * Registers the personal data exporter for each WordCamp post type.
+ *
+ * @param array $exporters
+ *
+ * @return array
+ */
+function register_personal_data_exporters( $exporters ) {
+       $exporters['wcb-reimbursements'] = array(
+               'exporter_friendly_name' => __( 'WordCamp Reimbursement Requests', 'wordcamporg' ),
+               'callback'               => __NAMESPACE__ . '\reimbursements_exporter',
+       );
+
+       $exporters['wcb-vendor-payments'] = array(
+               'exporter_friendly_name' => __( 'WordCamp Vendor Payment Requests', 'wordcamporg' ),
+               'callback'               => __NAMESPACE__ . '\vendor_payment_exporter',
+       );
+
+       return $exporters;
+}
+
+/**
+ * Finds and exports personal data associated with an email address in a vendor payment request
+ *
+ * @param string $email_address
+ * @param int $page
+ *
+ * @return array
+ */
+function vendor_payment_exporter( $email_address, $page ) {
+
+       $results = array(
+               'data' => array(),
+               'done' => true,
+       );
+
+       $vendor_payment_requests = get_post_wp_query( \WCP_Payment_Request::POST_TYPE, $page, $email_address );
+
+       if ( empty( $vendor_payment_requests ) ) {
+               return $results;
+       }
+
+       $data_to_export = array();
+       foreach ( $vendor_payment_requests->posts as $post ) {
+               $vendor_payment_exp_data = array();
+               $meta                    = get_post_meta( $post->ID );
+
+               $vendor_payment_exp_data[] = [
+                       'name'  => __( 'Title', 'wordcamporg' ),
+                       'value' => $post->post_title,
+               ];
+               $vendor_payment_exp_data[] = [
+                       'name'  => __( 'Date', 'wordcamporg' ),
+                       'value' => $post->post_date,
+               ];
+
+               $vendor_payment_exp_data = array_merge(
+                       $vendor_payment_exp_data, get_meta_details( $meta, \WCP_Payment_Request::POST_TYPE )
+               );
+
+               if ( ! empty( $vendor_payment_exp_data ) ) {
+                       $data_to_export[] = array(
+                               'group_id'    => \WCP_Payment_Request::POST_TYPE,
+                               'group_label' => __( 'WordCamp Vendor Payments', 'wordcamporg' ),
+                               'item_id'     => \WCP_Payment_Request::POST_TYPE . "-{$post->ID}",
+                               'data'        => $vendor_payment_exp_data,
+                       );
+               }
+       }
+
+       $results['done'] = $vendor_payment_requests->max_num_pages <= $page;
+       $results['data'] = $data_to_export;
+
+       return $results;
+}
+
+/**
+ * Finds and exports personal data associated with an email address in a Reimbursement Request.
+ *
+ * @param string $email_address
+ * @param int $page
+ *
+ * @return array
+ */
+function reimbursements_exporter( $email_address, $page ) {
+
+       $results = array(
+               'data' => array(),
+               'done' => true,
+       );
+
+       $reimbursements = get_post_wp_query( Reimbursement_Requests\POST_TYPE, $page, $email_address );
+
+       if ( empty( $reimbursements ) ) {
+               return $results;
+       }
+
+       $data_to_export = array();
+       foreach ( $reimbursements->posts as $post ) {
+               $reimbursement_data_to_export = array();
+               $meta                         = get_post_meta( $post->ID );
+
+               $reimbursement_data_to_export[] = [
+                       'name'  => __( 'Title', 'wordcamporg' ),
+                       'value' => $post->post_title,
+               ];
+               $reimbursement_data_to_export[] = [
+                       'name'  => __( 'Date', 'wordcamporg' ),
+                       'value' => $post->post_date,
+               ];
+
+               // meta fields
+               $reimbursement_data_to_export = array_merge(
+                       $reimbursement_data_to_export, get_meta_details( $meta, Reimbursement_Requests\POST_TYPE )
+               );
+
+
+               if ( ! empty( $reimbursement_data_to_export ) ) {
+                       $data_to_export[] = array(
+                               'group_id'    => Reimbursement_Requests\POST_TYPE,
+                               'group_label' => __( 'WordCamp Reimbursement Request', 'wordcamporg' ),
+                               'item_id'     => Reimbursement_Requests\POST_TYPE . "-{$post->ID}",
+                               'data'        => $reimbursement_data_to_export,
+                       );
+               }
+       }
+
+       $results['done'] = $reimbursements->max_num_pages <= $page;
+       $results['data'] = $data_to_export;
+
+       return $results;
+}
+
+/**
+ * Helper function, to build and return WP_Query object for fetching posts that should be considered for exporting data
+ *
+ * We use `_camppayments_vendor_email_address` as the key for `payment_request`, instead of author email,
+ * because the vendor contact details could be of an individual (instead of a business), and thus is a potential PII
+ *
+ * @param $query_type string
+ * @param $page integer
+ * @param $email_address string Email address of the entity making the request
+ *
+ * @return null|WP_Query
+ */
+function get_post_wp_query( $query_type, $page, $email_address ) {
+
+       $query_args = array(
+               'post_type'      => $query_type,
+               'post_status'    => 'any',
+               'number_posts'   => - 1,
+               'posts_per_page' => 20,
+               'paged'          => $page,
+       );
+
+       switch ( $query_type ) {
+               case Reimbursement_Requests\POST_TYPE :
+                       $user = get_user_by( 'email', $email_address );
+
+                       if ( empty( $user ) ) {
+                               return null;
+                       }
+
+                       $query_args = array_merge( $query_args, array( 'post_author' => $user->ID ) );
+                       break;
+               case \WCP_Payment_Request::POST_TYPE :
+                       $query_args['meta_query'] = [
+                               'relation' => 'AND',
+                       ];
+
+                       $query_args['meta_query'][] = [
+                               'key'   => '_camppayments_vendor_email_address',
+                               'value' => $email_address,
+                       ];
+                       break;
+               default :
+                       return null;
+       }
+
+       return new WP_Query( $query_args );
+}
+
+/**
+ * @param $meta array meta object of post, as retrieved by `get_post_meta( $post->ID )`
+ * @param $post_type string post_type . could be one of wcb_reimbursement or wcp_payment_request
+ *
+ * @return array Details of the reimbursement request
+ */
+function get_meta_details( $meta, $post_type ) {
+       $meta_details = array();
+       foreach ( get_meta_fields_mapping( $post_type ) as $meta_field => $meta_field_name ) {
+               $data = isset( $meta[ $meta_field ] ) ? $meta[ $meta_field ] : null;
+               if ( ! empty( $data ) && is_array( $data ) && ! empty( $data[0] ) ) {
+                       $meta_details[] = [
+                               'name'  => $meta_field_name,
+                               'value' => $meta [ $meta_field ][0],
+                       ];
+               }
+       }
+
+       return $meta_details;
+}
+
+/**
+ * Returns array of meta fields and their titles that we want to allow export for.
+ *
+ * @param $post_type string
+ *
+ * @return array
+ */
+function get_meta_fields_mapping( $post_type ) {
+       $mapping_fields = array();
+
+       if ( Reimbursement_Requests\POST_TYPE === $post_type ) {
+               $prefix = '_wcbrr_';
+               $mapping_fields = array_merge(
+                       $mapping_fields,
+                       array(
+                               $prefix . 'name_of_payer'               => __( 'Payer Name', 'wordcamporg' ),
+                               $prefix . 'currency'                    => __( 'Currency', 'wordcamporg' ),
+                               $prefix . 'payment_method'              => __( 'Payment Method', 'wordcamporg' ),
+
+                               // Payment Method - Direct Deposit
+                               $prefix . 'ach_bank_name'               => __( 'Bank Name', 'wordcamporg' ),
+                               $prefix . 'ach_account_type'            => __( 'Account Type', 'wordcamporg' ),
+                               $prefix . 'ach_routing_number'          => __( 'Routing Number', 'wordcamporg' ),
+                               $prefix . 'ach_account_number'          => __( 'Account Number', 'wordcamporg' ),
+                               $prefix . 'ach_account_holder_name'     => __( 'Account Holder Name', 'wordcamporg' ),
+
+                               // Payment Method - Check
+                               $prefix . 'payable_to'                  => __( 'Payable To', 'wordcamporg' ),
+                               $prefix . 'check_street_address'        => __( 'Street Address', 'wordcamporg' ),
+                               $prefix . 'check_city'                  => __( 'City', 'wordcamporg' ),
+                               $prefix . 'check_state'                 => __( 'State / Province', 'wordcamporg' ),
+                               $prefix . 'check_zip_code'              => __( 'ZIP / Postal Code', 'wordcamporg' ),
+                               $prefix . 'check_country'               => __( 'Country', 'wordcamporg' ),
+
+                               // Payment Method - Wire
+                               $prefix . 'bank_name'                   => __( 'Beneficiary’s Bank Name', 'wordcamporg' ),
+                               $prefix . 'bank_street_address'         => __( 'Beneficiary’s Bank Street Address', 'wordcamporg' ),
+                               $prefix . 'bank_city'                   => __( 'Beneficiary’s Bank City', 'wordcamporg' ),
+                               $prefix . 'bank_state'                  => __( 'Beneficiary’s Bank State / Province', 'wordcamporg' ),
+                               $prefix . 'bank_zip_code'               => __( 'Beneficiary’s Bank ZIP / Postal Code', 'wordcamporg' ),
+                               $prefix . 'bank_country_iso3166'        => __( 'Beneficiary’s Bank Country', 'wordcamporg' ),
+                               $prefix . 'bank_bic'                    => __( 'Beneficiary’s Bank SWIFT BIC', 'wordcamporg' ),
+                               $prefix . 'beneficiary_account_number'  => __( 'Beneficiary’s Account Number or IBAN', 'wordcamporg' ),
+
+                               // Intermediary bank details
+                               $prefix . 'interm_bank_name'            => __( 'Intermediary Bank Name', 'wordcamporg' ),
+                               $prefix . 'interm_bank_street_address'  => __( 'Intermediary Bank Street Address', 'wordcamporg' ),
+                               $prefix . 'interm_bank_city'            => __( 'Intermediary Bank City', 'wordcamporg' ),
+                               $prefix . 'interm_bank_state'           => __( 'Intermediary Bank State / Province', 'wordcamporg' ),
+                               $prefix . 'interm_bank_zip_code'        => __( 'Intermediary Bank ZIP / Postal Code', 'wordcamporg' ),
+                               $prefix . 'interm_bank_country_iso3166' => __( 'Intermediary Bank Country', 'wordcamporg' ),
+                               $prefix . 'interm_bank_swift'           => __( 'Intermediary Bank SWIFT BIC', 'wordcamporg' ),
+                               $prefix . 'interm_bank_account'         => __( 'Intermediary Bank Account', 'wordcamporg' ),
+
+                               $prefix . 'beneficiary_name'            => __( 'Beneficiary’s Name', 'wordcamporg' ),
+                               $prefix . 'beneficiary_street_address'  => __( 'Beneficiary’s Street Address', 'wordcamporg' ),
+                               $prefix . 'beneficiary_city'            => __( 'Beneficiary’s City', 'wordcamporg' ),
+                               $prefix . 'beneficiary_state'           => __( 'Beneficiary’s State / Province', 'wordcamporg' ),
+                               $prefix . 'beneficiary_zip_code'        => __( 'Beneficiary’s ZIP / Postal Code', 'wordcamporg' ),
+                               $prefix . 'beneficiary_country_iso3166' => __( 'Beneficiary’s Country', 'wordcamporg' ),
+
+                       )
+               );
+       } elseif ( \WCP_Payment_Request::POST_TYPE === $post_type ) {
+               $prefix = '_camppayments_';
+               $mapping_fields = array_merge(
+                       $mapping_fields,
+                       array(
+                               // Vendor payment fields
+                               $prefix . 'description'            => __( 'Description', 'wordcamporg' ),
+                               $prefix . 'general_notes'          => __( 'Notes', 'wordcamporg' ),
+                               $prefix . 'vendor_name'            => __( 'Name', 'wordcamporg' ),
+                               $prefix . 'vendor_email_address'   => __( 'Email Address', 'wordcamporg' ),
+                               $prefix . 'vendor_contact_person'  => __( 'Contact Person', 'wordcamporg' ),
+                               $prefix . 'vendor_street_address'  => __( 'Street Address', 'wordcamporg' ),
+                               $prefix . 'vendor_city'            => __( 'City', 'wordcamporg' ),
+                               $prefix . 'vendor_state'           => __( 'State / Province', 'wordcamporg' ),
+                               $prefix . 'vendor_zip_code'        => __( 'ZIP / Postal Code', 'wordcamporg' ),
+                               $prefix . 'vendor_country_iso3166' => __( 'Country', 'wordcamporg' ),
+                       )
+               );
+       }
+
+       return $mapping_fields;
+}
+
</ins></span></pre>
</div>
</div>

</body>
</html>