Changeset 6834 for sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-qbo/wordcamp-qbo.php
- Timestamp:
- 03/07/2018 01:45:42 AM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-qbo/wordcamp-qbo.php
r6833 r6834 23 23 24 24 public static function load_options() { 25 if ( isset( self::$options ) ) 25 if ( isset( self::$options ) ) { 26 26 return self::$options; 27 } 27 28 28 29 self::$options = wp_parse_args( get_option( 'wordcamp-qbo', array() ), array( … … 50 51 51 52 $init_options = wp_parse_args( apply_filters( 'wordcamp_qbo_options', array() ), array( 52 'app_token' => '',53 'consumer_key' => '',53 'app_token' => '', 54 'consumer_key' => '', 54 55 'consumer_secret' => '', 55 'hmac_key' => '',56 57 'categories_map' => array(),56 'hmac_key' => '', 57 58 'categories_map' => array(), 58 59 ) ); 59 60 60 foreach ( $init_options as $key => $value ) 61 foreach ( $init_options as $key => $value ) { 61 62 self::$$key = $value; 63 } 62 64 63 65 // There's no point in doing anything if we don't have the secrets. 64 if ( empty( self::$consumer_key ) ) 66 if ( empty( self::$consumer_key ) ) { 65 67 return; 68 } 66 69 67 70 self::$api_base_url = sprintf( … … 87 90 public static function rest_api_init() { 88 91 register_rest_route( 'wordcamp-qbo/v1', '/expense', array( 89 'methods' => 'GET, POST',92 'methods' => 'GET, POST', 90 93 'callback' => array( __CLASS__, 'rest_callback_expense' ), 91 94 ) ); 92 95 93 96 register_rest_route( 'wordcamp-qbo/v1', '/invoice', array( 94 'methods' => 'GET, POST',97 'methods' => 'GET, POST', 95 98 'callback' => array( __CLASS__, 'rest_callback_invoice' ), 96 99 ) ); 97 100 98 101 register_rest_route( 'wordcamp-qbo/v1', '/invoice_pdf', array( 99 'methods' => 'GET',102 'methods' => 'GET', 100 103 'callback' => array( __CLASS__, 'rest_callback_invoice_pdf' ), 101 104 ) ); 102 105 103 106 register_rest_route( 'wordcamp-qbo/v1', '/paid_invoices', array( 104 'methods' => 'GET',107 'methods' => 'GET', 105 108 'callback' => array( __CLASS__, 'rest_callback_paid_invoices' ), 106 109 ) ); … … 113 116 */ 114 117 public static function rest_callback_expense( $request ) { 115 if ( ! self::_is_valid_request( $request ) ) 118 if ( ! self::_is_valid_request( $request ) ) { 116 119 return new WP_Error( 'unauthorized', 'Unauthorized', array( 'status' => 401 ) ); 120 } 117 121 118 122 self::load_options(); … … 121 125 122 126 $amount = floatval( $request->get_param( 'amount' ) ); 123 if ( ! $amount ) 127 if ( ! $amount ) { 124 128 return new WP_Error( 'error', 'An amount was not given.' ); 129 } 125 130 126 131 $description = $request->get_param( 'description' ); 127 if ( empty( $description ) ) 132 if ( empty( $description ) ) { 128 133 return new WP_Error( 'error', 'The expense description can not be empty.' ); 134 } 129 135 130 136 $category = $request->get_param( 'category' ); 131 if ( empty( $category ) || ! array_key_exists( $category, self::$categories_map ) ) 137 if ( empty( $category ) || ! array_key_exists( $category, self::$categories_map ) ) { 132 138 return new WP_Error( 'error', 'The category you have picked is invalid.' ); 139 } 133 140 134 141 $date = $request->get_param( 'date' ); 135 if ( empty( $date ) ) 142 if ( empty( $date ) ) { 136 143 return new WP_Error( 'error', 'The expense date can not be empty.' ); 144 } 137 145 138 146 $date = absint( $date ); 139 147 140 148 $class = $request->get_param( 'class' ); 141 if ( empty( $class ) ) 149 if ( empty( $class ) ) { 142 150 return new WP_Error( 'error', 'You need to set a class.' ); 151 } 143 152 144 153 $classes = self::_get_classes(); 145 if ( ! array_key_exists( $class, $classes ) ) 154 if ( ! array_key_exists( $class, $classes ) ) { 146 155 return new WP_Error( 'error', 'Unknown class.' ); 156 } 147 157 148 158 $class = array( 149 159 'value' => $class, 150 'name' => $classes[ $class ],160 'name' => $classes[ $class ], 151 161 ); 152 162 153 163 $payload = array( 154 'AccountRef' => self::$account,155 'TxnDate' => gmdate( 'Y-m-d', $date ),164 'AccountRef' => self::$account, 165 'TxnDate' => gmdate( 'Y-m-d', $date ), 156 166 'PaymentType' => 'Cash', 157 'Line' => array(167 'Line' => array( 158 168 array( 159 'Id' => 1,160 'Description' => $description,161 'Amount' => $amount,162 'DetailType' => 'AccountBasedExpenseLineDetail',169 'Id' => 1, 170 'Description' => $description, 171 'Amount' => $amount, 172 'DetailType' => 'AccountBasedExpenseLineDetail', 163 173 'AccountBasedExpenseLineDetail' => array( 164 'ClassRef' => $class,174 'ClassRef' => $class, 165 175 'AccountRef' => self::$categories_map[ $category ], 166 176 ), … … 176 186 177 187 $oauth_header = $oauth->get_oauth_header( 'GET', $request_url ); 178 $response = wp_remote_get( $request_url, array(188 $response = wp_remote_get( $request_url, array( 179 189 'timeout' => self::REMOTE_REQUEST_TIMEOUT, 180 190 'headers' => array( 181 191 'Authorization' => $oauth_header, 182 'Accept' => 'application/json',192 'Accept' => 'application/json', 183 193 ), 184 194 ) ); 185 195 Logger\log( 'remote_request_sync_token', compact( 'response' ) ); 186 196 187 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) != 200 ) 197 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) != 200 ) { 188 198 return new WP_Error( 'error', 'Could not find purchase to update.' ); 199 } 189 200 190 201 $body = json_decode( wp_remote_retrieve_body( $response ), true ); 191 if ( ! isset( $body['Purchase']['SyncToken'] ) ) 202 if ( ! isset( $body['Purchase']['SyncToken'] ) ) { 192 203 return new WP_Error( 'error', 'Could not decode purchase for update.' ); 204 } 193 205 194 206 $payload['SyncToken'] = $body['Purchase']['SyncToken']; … … 196 208 } 197 209 198 $payload = json_encode( $payload );210 $payload = json_encode( $payload ); 199 211 $request_url = esc_url_raw( sprintf( '%s/v3/company/%d/purchase', 200 212 self::$api_base_url, self::$options['auth']['realmId'] ) ); 201 213 202 214 $oauth_header = $oauth->get_oauth_header( 'POST', $request_url, $payload ); 203 $response = wp_remote_post( $request_url, array(215 $response = wp_remote_post( $request_url, array( 204 216 'timeout' => self::REMOTE_REQUEST_TIMEOUT, 205 217 'headers' => array( 206 218 'Authorization' => $oauth_header, 207 'Accept' => 'application/json',208 'Content-Type' => 'application/json',209 ), 210 'body' => $payload,219 'Accept' => 'application/json', 220 'Content-Type' => 'application/json', 221 ), 222 'body' => $payload, 211 223 ) ); 212 224 Logger\log( 'remote_request_create_expense', compact( 'payload', 'response' ) ); 213 225 214 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) != 200 ) 226 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) != 200 ) { 215 227 return new WP_Error( 'error', 'Could not create purchase.' ); 228 } 216 229 217 230 $body = json_decode( wp_remote_retrieve_body( $response ), true ); 218 if ( empty( $body ) ) 231 if ( empty( $body ) ) { 219 232 return new WP_Error( 'error', 'Could not decode create purchase result.' ); 233 } 220 234 221 235 return array( … … 248 262 249 263 $args = array( 250 'query' => 'SELECT * FROM Class MAXRESULTS 1000',264 'query' => 'SELECT * FROM Class MAXRESULTS 1000', 251 265 'minorversion' => 4, 252 266 ); … … 256 270 257 271 $oauth_header = $oauth->get_oauth_header( 'GET', $request_url, $args ); 258 $response = wp_remote_get(272 $response = wp_remote_get( 259 273 esc_url_raw( add_query_arg( $args, $request_url ) ), 260 274 array( … … 262 276 'headers' => array( 263 277 'Authorization' => $oauth_header, 264 'Accept' => 'application/json',265 ) 278 'Accept' => 'application/json', 279 ), 266 280 ) 267 281 ); … … 475 489 */ 476 490 $description_limit = abs( 995 - strlen( $payment_instructions ) ); 477 $customer_memo = sprintf(491 $customer_memo = sprintf( 478 492 "%s\n\n%s", 479 493 substr( $description, 0, $description_limit ), … … 502 516 'Line' => array( 503 517 array( 504 'Amount' => $amount,505 'Description' => $line_description,506 'DetailType' => 'SalesItemLineDetail',518 'Amount' => $amount, 519 'Description' => $line_description, 520 'DetailType' => 'SalesItemLineDetail', 507 521 508 522 'SalesItemLineDetail' => array( 509 'ItemRef' => array(523 'ItemRef' => array( 510 524 'value' => '20', // Sponsorship 511 525 ), 512 526 513 'ClassRef' => array(527 'ClassRef' => array( 514 528 'value' => $class_id, 515 529 ), … … 517 531 'UnitPrice' => $amount, 518 532 'Qty' => 1, 519 ) 520 ) 521 ), 522 523 'CustomerRef' => array(533 ), 534 ), 535 ), 536 537 'CustomerRef' => array( 524 538 'value' => $customer_id, 525 539 ), … … 533 547 ), 534 548 535 'BillEmail' => array(549 'BillEmail' => array( 536 550 'Address' => $customer_email, 537 551 ), … … 566 580 'Content-Type' => 'application/json', 567 581 ), 568 'body' => $payload,582 'body' => $payload, 569 583 ); 570 584 571 585 return array( 572 586 'url' => $request_url, 573 'args' => $args 587 'args' => $args, 574 588 ); 575 589 } … … 630 644 'Content-Type' => 'application/octet-stream', 631 645 ), 632 'body' => '',646 'body' => '', 633 647 ); 634 648 … … 717 731 'Content-Type' => 'application/pdf', 718 732 ), 719 'body' => '',733 'body' => '', 720 734 ); 721 735 … … 946 960 947 961 'CurrencyRef' => array( 948 'value' => $currency_code 949 ), 950 951 'PreferredDeliveryMethod' => 'Email',952 953 'GivenName' => $sponsor['first-name'],954 'FamilyName' => $sponsor['last-name'],955 'CompanyName' => $sponsor['company-name'],956 'DisplayName' => sprintf( '%s - %s', $sponsor['company-name'], $currency_code ),957 'PrintOnCheckName' => $sponsor['company-name'],958 959 'PrimaryPhone' => array(962 'value' => $currency_code, 963 ), 964 965 'PreferredDeliveryMethod' => 'Email', 966 967 'GivenName' => $sponsor['first-name'], 968 'FamilyName' => $sponsor['last-name'], 969 'CompanyName' => $sponsor['company-name'], 970 'DisplayName' => sprintf( '%s - %s', $sponsor['company-name'], $currency_code ), 971 'PrintOnCheckName' => $sponsor['company-name'], 972 973 'PrimaryPhone' => array( 960 974 'FreeFormNumber' => $sponsor['phone-number'], 961 975 ), 962 976 963 'PrimaryEmailAddr' => array(977 'PrimaryEmailAddr' => array( 964 978 'Address' => $sponsor['email-address'], 965 979 ), … … 985 999 'Content-Type' => 'application/json', 986 1000 ), 987 'body' => $payload,1001 'body' => $payload, 988 1002 ); 989 1003 … … 1102 1116 */ 1103 1117 private static function _is_valid_request( $request ) { 1104 if ( ! $request->get_header( 'authorization' ) ) 1118 if ( ! $request->get_header( 'authorization' ) ) { 1105 1119 return false; 1106 1107 if ( ! preg_match( '#^wordcamp-qbo-hmac (.+)$#', $request->get_header( 'authorization' ), $matches ) ) 1120 } 1121 1122 if ( ! preg_match( '#^wordcamp-qbo-hmac (.+)$#', $request->get_header( 'authorization' ), $matches ) ) { 1108 1123 return false; 1109 1110 $given_hmac = $matches[1]; 1124 } 1125 1126 $given_hmac = $matches[1]; 1111 1127 $request_url = esc_url_raw( home_url( parse_url( home_url( $_SERVER['REQUEST_URI'] ), PHP_URL_PATH ) ) ); 1112 $payload = json_encode( array( strtolower( $request->get_method() ), strtolower( $request_url ), 1113 $request->get_body(), $request->get_query_params() ) ); 1128 $payload = json_encode( array( 1129 strtolower( $request->get_method() ), 1130 strtolower( $request_url ), 1131 $request->get_body(), 1132 $request->get_query_params(), 1133 ) ); 1114 1134 1115 1135 return hash_equals( hash_hmac( 'sha256', $payload, self::$hmac_key ), $given_hmac ); … … 1128 1148 */ 1129 1149 public static function maybe_oauth_request() { 1130 if ( empty( $_GET['wordcamp-qbo-oauth-request'] ) ) 1150 if ( empty( $_GET['wordcamp-qbo-oauth-request'] ) ) { 1131 1151 return; 1132 1133 if ( empty( $_GET['wordcamp-qbo-oauth-nonce'] ) || ! wp_verify_nonce( $_GET['wordcamp-qbo-oauth-nonce'], 'oauth-request' ) ) 1152 } 1153 1154 if ( empty( $_GET['wordcamp-qbo-oauth-nonce'] ) || ! wp_verify_nonce( $_GET['wordcamp-qbo-oauth-nonce'], 'oauth-request' ) ) { 1134 1155 wp_die( 'Could not verify nonce.' ); 1156 } 1135 1157 1136 1158 self::load_options(); … … 1140 1162 1141 1163 // We don't have an access token yet. 1142 $request_url = 'https://oauth.intuit.com/oauth/v1/get_request_token';1164 $request_url = 'https://oauth.intuit.com/oauth/v1/get_request_token'; 1143 1165 $callback_url = esc_url_raw( add_query_arg( array( 1144 1166 'wordcamp-qbo-oauth-request' => 1, 1145 'wordcamp-qbo-oauth-nonce' => wp_create_nonce( 'oauth-request' ),1167 'wordcamp-qbo-oauth-nonce' => wp_create_nonce( 'oauth-request' ), 1146 1168 ), admin_url() ) ); 1147 1169 1148 1170 $request_token = $oauth->get_request_token( $request_url, $callback_url ); 1149 if ( is_wp_error( $request_token ) ) 1171 if ( is_wp_error( $request_token ) ) { 1150 1172 wp_die( $request_token->get_error_message() ); 1173 } 1151 1174 1152 1175 update_user_meta( get_current_user_id(), 'wordcamp-qbo-oauth', $request_token ); … … 1161 1184 $request_token = get_user_meta( get_current_user_id(), 'wordcamp-qbo-oauth', true ); 1162 1185 1163 if ( $request_token['oauth_token'] != $_GET['oauth_token'] ) 1186 if ( $request_token['oauth_token'] != $_GET['oauth_token'] ) { 1164 1187 wp_die( 'Could not verify OAuth token.' ); 1165 1166 if ( empty( $_GET['oauth_verifier'] ) ) 1188 } 1189 1190 if ( empty( $_GET['oauth_verifier'] ) ) { 1167 1191 wp_die( 'Could not obtain OAuth verifier.' ); 1192 } 1168 1193 1169 1194 $oauth->set_token( $request_token['oauth_token'], $request_token['oauth_token_secret'] ); … … 1172 1197 $access_token = $oauth->get_access_token( $request_url, $_GET['oauth_verifier'] ); 1173 1198 1174 if ( is_wp_error( $access_token ) ) 1199 if ( is_wp_error( $access_token ) ) { 1175 1200 wp_die( 'Could not obtain an access token.' ); 1201 } 1176 1202 1177 1203 // We have an access token. 1178 1204 $data = array( 1179 'oauth_token' => $access_token['oauth_token'],1205 'oauth_token' => $access_token['oauth_token'], 1180 1206 'oauth_token_secret' => $access_token['oauth_token_secret'], 1181 'realmId' => $_GET['realmId'],1207 'realmId' => $_GET['realmId'], 1182 1208 ); 1183 1209 … … 1185 1211 1186 1212 $oauth->set_token( self::$options['auth']['oauth_token'], self::$options['auth']['oauth_token_secret'] ); 1187 $request_url = sprintf( '%s/v3/company/%d/companyinfo/%d', 1188 self::$api_base_url, self::$options['auth']['realmId'], self::$options['auth']['realmId'] ); 1213 1214 $request_url = sprintf( 1215 '%s/v3/company/%d/companyinfo/%d', 1216 self::$api_base_url, 1217 self::$options['auth']['realmId'], 1218 self::$options['auth']['realmId'] 1219 ); 1189 1220 1190 1221 $oauth_header = $oauth->get_oauth_header( 'GET', $request_url ); 1191 $response = wp_remote_get( $request_url, array(1222 $response = wp_remote_get( $request_url, array( 1192 1223 'timeout' => self::REMOTE_REQUEST_TIMEOUT, 1193 1224 'headers' => array( 1194 1225 'Authorization' => $oauth_header, 1195 'Accept' => 'application/json',1196 ) 1226 'Accept' => 'application/json', 1227 ), 1197 1228 ) ); 1198 1229 Logger\log( 'remote_request', compact( 'response' ) ); … … 1208 1239 $company_name = $body['CompanyInfo']['CompanyName']; 1209 1240 1210 self::$options['auth']['name'] = $company_name;1241 self::$options['auth']['name'] = $company_name; 1211 1242 self::$options['auth']['timestamp'] = time(); 1212 1243 self::update_options();
Note: See TracChangeset
for help on using the changeset viewer.