';
$html .= '
Business Loan Warrior — Funding Application ';
$html .= 'Application #' . $e( $d['entry_id'] ) . ' · Submitted ' . $e( $signedf ) . '
';
$html .= 'Funding Request '
. $row( 'Amount requested', $d['amount'] )
. $row( 'Time in business', $d['time_in_biz'] )
. $row( 'Average monthly sales', $d['monthly_sales'] )
. $row( 'When funds are needed', $d['when_needed'] )
. $row( 'Use of funds', $d['use_of_funds'] )
. '
';
$html .= 'Business '
. $row( 'Business name', $d['business_name'] )
. $row( 'Entity type', $d['entity_type'] )
. $row( 'Federal Tax ID', $d['tax_id'] )
. $row( 'Incorporation date', $d['inc_date'] )
. $row( 'Business address', $d['biz_address'] )
. $row( 'Business phone', $d['biz_phone'] )
. $row( 'Business email', $d['biz_email'] )
. $row( 'Website', $d['website'] )
. $row( 'Customers', $d['customers'] )
. $row( 'Business description', $d['description'] )
. '
';
$html .= 'Owner '
. $row( 'Name', trim( $d['first_name'] . ' ' . $d['last_name'] ) )
. $row( 'Email', $d['email'] )
. $row( 'Phone', $d['phone'] )
. $row( 'Ownership %', $d['ownership'] )
. $row( 'Date of birth', $d['dob'] )
. $row( 'Social Security Number', $d['ssn'] )
. $row( 'Home address', $d['home_address'] )
. '
';
$names = array();
foreach ( $d['files'] as $f ) {
$names[] = $f['name'];
}
$html .= 'Documents Provided ' . $row( 'Bank statements', $names ? implode( "\n", $names ) : '' ) . '
';
$html .= 'Electronic Signature ';
$html .= '' . $e( $d['consent_text'] ) . '
';
$html .= 'Authorization box checked: ' . ( '' !== $d['esign_consent'] ? 'Yes' : 'No' ) . '
';
$html .= '' . $e( $d['esign_name'] ) . '
';
$html .= 'Electronically signed by ' . $e( $d['esign_name'] ) . ' on ' . $e( $signedf )
. ' IP address: ' . $e( $d['ip'] ) . ' · Signer email: ' . $e( $d['email'] ) . ' · Application #' . $e( $d['entry_id'] )
. ' Device: ' . $e( $d['user_agent'] ) . '
';
try {
$mpdf = new \Mpdf\Mpdf(
array(
'tempDir' => blw_sf_private_dir( 'mpdf-tmp' ),
'format' => 'Letter',
'margin_top' => 14,
'margin_bottom' => 14,
)
);
$mpdf->SetTitle( 'Funding Application #' . $d['entry_id'] );
$mpdf->SetFooter( 'Business Loan Warrior · Application #' . $d['entry_id'] . ' · Page {PAGENO} of {nbpg}' );
$mpdf->WriteHTML( $html );
$safe = sanitize_file_name( 'BLW-Application-' . $d['entry_id'] . '-' . $d['business_name'] . '.pdf' );
$path = trailingslashit( blw_sf_private_dir( 'applications' ) ) . $safe;
$mpdf->Output( $path, \Mpdf\Output\Destination::FILE );
return array( 'path' => $path, 'name' => $safe );
} catch ( \Throwable $t ) {
return new WP_Error( 'blw_sf_pdf', 'PDF build failed: ' . $t->getMessage() );
}
}
}
/* ---------------------------------------------------------------------------
* Sync one entry
* ------------------------------------------------------------------------- */
if ( ! function_exists( 'blw_sf_upload_file' ) ) {
function blw_sf_upload_file( $opp_id, $path, $name ) {
if ( ! file_exists( $path ) ) {
return new WP_Error( 'blw_sf_file', 'File missing on server: ' . basename( $path ) );
}
$size = filesize( $path );
if ( $size > 25 * MB_IN_BYTES ) {
return new WP_Error( 'blw_sf_file', 'File too large for API upload: ' . basename( $path ) );
}
return blw_sf_api(
'POST',
'/sobjects/ContentVersion',
array(
'Title' => preg_replace( '/\.[^.]+$/', '', $name ),
'PathOnClient' => $name,
'VersionData' => base64_encode( file_get_contents( $path ) ),
'FirstPublishLocationId' => $opp_id,
)
);
}
}
if ( ! function_exists( 'blw_sf_sync_entry' ) ) {
function blw_sf_sync_entry( $entry_id ) {
$entry_id = (int) $entry_id;
$done = function_exists( 'wpforms' ) ? wpforms()->obj( 'entry_meta' )->get_meta( array( 'entry_id' => $entry_id, 'type' => 'blw_sf_opportunity', 'number' => 1 ) ) : array();
if ( ! empty( $done ) ) {
blw_sf_log( 'Entry ' . $entry_id . ': already synced, skipped.' );
return;
}
$d = blw_sf_entry_data( $entry_id );
if ( is_wp_error( $d ) ) {
blw_sf_log( 'Entry ' . $entry_id . ': ' . $d->get_error_message() );
return;
}
// 1. Contact by email -> reuse Account; else create Account + Contact.
$account_id = '';
$contact_id = '';
if ( $d['email'] ) {
$q = blw_sf_api( 'GET', '/query?q=' . rawurlencode( "SELECT Id, AccountId FROM Contact WHERE Email = '" . blw_sf_soql_escape( $d['email'] ) . "' ORDER BY CreatedDate DESC LIMIT 1" ) );
if ( ! is_wp_error( $q ) && ! empty( $q['records'][0] ) ) {
$contact_id = $q['records'][0]['Id'];
$account_id = (string) $q['records'][0]['AccountId'];
}
}
$biz_name = $d['business_name'] ? $d['business_name'] : trim( $d['first_name'] . ' ' . $d['last_name'] );
if ( ! $account_id && $d['business_name'] ) {
// A business can have several owners: a second owner applying for the same business joins the same Account.
$rt_clause = blw_sf_merchant_rt() ? " AND RecordTypeId = '" . blw_sf_merchant_rt() . "'" : '';
$q = blw_sf_api( 'GET', '/query?q=' . rawurlencode( "SELECT Id FROM Account WHERE Name = '" . blw_sf_soql_escape( $d['business_name'] ) . "'" . $rt_clause . ' ORDER BY CreatedDate DESC LIMIT 1' ) );
if ( ! is_wp_error( $q ) && ! empty( $q['records'][0] ) ) {
$account_id = $q['records'][0]['Id'];
}
}
if ( ! $account_id ) {
$acc = blw_sf_api(
'POST',
'/sobjects/Account',
array_filter(
array(
'Name' => $biz_name,
'RecordTypeId' => blw_sf_merchant_rt(),
'Phone' => $d['biz_phone'],
'Website' => $d['website'],
'BillingStreet' => $d['street'],
'BillingCity' => $d['city'],
'BillingState' => $d['state'],
'BillingPostalCode' => $d['zip'],
'Description' => $d['description'],
'AccountSource' => blw_sf_picklist_ok( 'Account', 'AccountSource', 'Web' ) ? 'Web' : '',
)
)
);
if ( is_wp_error( $acc ) ) {
blw_sf_log( 'Entry ' . $entry_id . ': ' . $acc->get_error_message() );
return;
}
$account_id = $acc['id'];
}
if ( ! $contact_id ) {
$con = blw_sf_api(
'POST',
'/sobjects/Contact',
array_filter(
array(
'AccountId' => $account_id,
'FirstName' => $d['first_name'],
'LastName' => $d['last_name'] ? $d['last_name'] : 'Unknown',
'Email' => $d['email'],
'MobilePhone' => $d['phone'],
'MailingStreet' => $d['home_address'],
'Title' => $d['ownership'] ? mb_substr( 'Owner (' . $d['ownership'] . ( false === strpos( $d['ownership'], '%' ) ? '%' : '' ) . ')', 0, 128 ) : 'Owner',
'LeadSource' => blw_sf_picklist_ok( 'Contact', 'LeadSource', 'Web' ) ? 'Web' : '',
)
)
);
if ( is_wp_error( $con ) ) {
blw_sf_log( 'Entry ' . $entry_id . ': ' . $con->get_error_message() );
return;
}
$contact_id = $con['id'];
}
// 2. Opportunity (uses the application fields already built in this org).
$amount = (float) preg_replace( '/[^0-9.]/', '', $d['amount'] );
// Monthly sales come in as a range (e.g. "$100,000 - $250,000"): store the low end, keep the range in Description.
$monthly = 0;
if ( preg_match( '/\$?\s*([\d,]+(?:\.\d+)?)/', $d['monthly_sales'], $m ) ) {
$monthly = (float) str_replace( ',', '', $m[1] );
}
$details = "Website application #{$d['entry_id']}\nAvg monthly sales (range selected): {$d['monthly_sales']}\nEntity: {$d['entity_type']}\nIncorporated: {$d['inc_date']}\nCustomers: {$d['customers']}\nOwnership: {$d['ownership']}\nBusiness email: {$d['biz_email']}\nHeard about us: {$d['heard_about']}\n\nE-signed by {$d['esign_name']} on {$d['submitted']} UTC from IP {$d['ip']}. Signed application PDF and bank statements are attached under Files.";
$fields = array(
'Name' => ( $d['business_name'] ? $d['business_name'] : trim( $d['first_name'] . ' ' . $d['last_name'] ) ) . ' - Web Application #' . $entry_id,
'AccountId' => $account_id,
'StageName' => blw_sf_opt( 'stage' ) ? blw_sf_opt( 'stage' ) : 'New / Contacted',
'CloseDate' => gmdate( 'Y-m-d', time() + 30 * DAY_IN_SECONDS ),
'Amount' => $amount > 0 ? $amount : null,
'Requested_Amount__c' => $amount > 0 ? round( $amount ) : null,
'Monthly_Revenue__c' => $monthly > 0 ? $monthly : null,
'Time_in_Business__c' => mb_substr( $d['time_in_biz'], 0, 100 ),
'Use_of_Fund__c' => mb_substr( $d['use_of_funds'], 0, 255 ),
'Funds_Needed_By__c' => mb_substr( $d['when_needed'], 0, 100 ),
'Entity_Type__c' => blw_sf_picklist_ok( 'Opportunity', 'Entity_Type__c', $d['entity_type'] ) ? $d['entity_type'] : null,
'LeadSource' => blw_sf_picklist_ok( 'Opportunity', 'LeadSource', 'Web' ) ? 'Web' : null,
'OwnerId' => blw_sf_opt( 'owner_id' ) ? blw_sf_opt( 'owner_id' ) : null,
'Description' => $details,
);
$opp = blw_sf_api( 'POST', '/sobjects/Opportunity', array_filter( $fields, function ( $x ) { return null !== $x && '' !== $x; } ) );
if ( is_wp_error( $opp ) ) {
blw_sf_log( 'Entry ' . $entry_id . ': ' . $opp->get_error_message() );
return;
}
$opp_id = $opp['id'];
blw_sf_api( 'POST', '/sobjects/OpportunityContactRole', array_filter( array( 'OpportunityId' => $opp_id, 'ContactId' => $contact_id, 'IsPrimary' => true, 'Role' => blw_sf_picklist_ok( 'OpportunityContactRole', 'Role', 'Decision Maker' ) ? 'Decision Maker' : '' ) ) );
// Record the link on the WPForms entry right away so a retry never duplicates the Opportunity.
wpforms()->obj( 'entry_meta' )->add(
array(
'entry_id' => $entry_id,
'form_id' => BLW_SF_FORM_ID,
'user_id' => 0,
'type' => 'blw_sf_opportunity',
'data' => $opp_id,
),
'entry_meta'
);
// 3. Signed application PDF + bank statements as Files.
$problems = array();
$pdf = blw_sf_build_pdf( $d );
if ( is_wp_error( $pdf ) ) {
$problems[] = $pdf->get_error_message();
} else {
$up = blw_sf_upload_file( $opp_id, $pdf['path'], $pdf['name'] );
if ( is_wp_error( $up ) ) {
$problems[] = $up->get_error_message();
}
}
foreach ( $d['files'] as $f ) {
$up = blw_sf_upload_file( $opp_id, $f['path'], $f['name'] );
if ( is_wp_error( $up ) ) {
$problems[] = $up->get_error_message();
}
}
wpforms()->obj( 'entry_meta' )->add(
array(
'entry_id' => $entry_id,
'form_id' => BLW_SF_FORM_ID,
'user_id' => 0,
'type' => 'note',
'data' => wpautop( 'Sent to Business Loan Warrior Salesforce: Opportunity ' . $opp_id . ( $problems ? '. Issues: ' . implode( '; ', $problems ) : ' with signed PDF and ' . count( $d['files'] ) . ' bank statement file(s).' ) ),
),
'entry_meta'
);
blw_sf_log( 'Entry ' . $entry_id . ': OK, Opportunity ' . $opp_id . ', files ' . count( $d['files'] ) . ( $problems ? ', issues: ' . implode( '; ', $problems ) : '' ) );
}
}
/* ---------------------------------------------------------------------------
* Hooks
* ------------------------------------------------------------------------- */
add_action( 'blw_sf_sync_entry', 'blw_sf_sync_entry', 10, 1 );
add_action(
'wpforms_process_complete',
function ( $fields, $entry, $form_data, $entry_id ) {
if ( (int) $form_data['id'] !== BLW_SF_FORM_ID || ! blw_sf_opt( 'enabled' ) ) {
return;
}
wp_schedule_single_event( time() + 10, 'blw_sf_sync_entry', array( (int) $entry_id ) );
if ( function_exists( 'spawn_cron' ) ) {
spawn_cron();
}
},
20,
4
);
/* ---------------------------------------------------------------------------
* Settings page: Settings > BLW Salesforce
* ------------------------------------------------------------------------- */
add_action(
'admin_menu',
function () {
add_options_page( 'BLW Salesforce', 'BLW Salesforce', 'manage_options', 'blw-salesforce', 'blw_sf_settings_page' );
}
);
if ( ! function_exists( 'blw_sf_settings_page' ) ) {
function blw_sf_settings_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$notice = '';
if ( isset( $_POST['blw_sf_action'] ) && check_admin_referer( 'blw_sf_settings' ) ) {
$action = sanitize_key( wp_unslash( $_POST['blw_sf_action'] ) );
$opts = get_option( 'blw_sf_settings', array() );
if ( 'save' === $action ) {
$opts['domain'] = esc_url_raw( wp_unslash( $_POST['domain'] ?? '' ) );
$opts['client_id'] = sanitize_text_field( wp_unslash( $_POST['client_id'] ?? '' ) );
if ( ! empty( $_POST['client_secret'] ) ) {
$opts['client_secret'] = sanitize_text_field( wp_unslash( $_POST['client_secret'] ) );
}
$opts['stage'] = sanitize_text_field( wp_unslash( $_POST['stage'] ?? '' ) );
$opts['owner_id'] = sanitize_text_field( wp_unslash( $_POST['owner_id'] ?? '' ) );
$opts['enabled'] = ! empty( $_POST['enabled'] ) ? 1 : 0;
update_option( 'blw_sf_settings', $opts, false );
delete_transient( 'blw_sf_token' );
$notice = 'Settings saved.';
} elseif ( 'test' === $action ) {
$r = blw_sf_api( 'GET', '/query?q=' . rawurlencode( 'SELECT Name FROM Organization' ) );
$notice = is_wp_error( $r ) ? 'Connection failed: ' . $r->get_error_message() : 'Connected to Salesforce org: ' . esc_html( $r['records'][0]['Name'] );
} elseif ( 'resend' === $action ) {
$id = absint( $_POST['entry_id'] ?? 0 );
if ( $id ) {
blw_sf_sync_entry( $id );
$notice = 'Sent entry #' . $id . '. Check the entry notes for the result.';
}
}
}
$o = get_option( 'blw_sf_settings', array() );
echo 'BLW Salesforce ';
if ( $notice ) {
echo '
' . esc_html( $notice ) . '
';
}
echo '
';
}
}
Skip to content