'','client_email'=>'','property_address'=>'']; $txt = @file_get_contents($file); if (!$txt) return $out; if (!preg_match('/^---\s*\R(.*?)\R---/s', $txt, $m)) return $out; $fm = $m[1]; $ctx = null; foreach (preg_split('/\R/', $fm) as $line) { if (preg_match('/^\s*client\s*:\s*$/', $line)) { $ctx='client'; continue; } if (preg_match('/^\s*property\s*:\s*$/', $line)) { $ctx='property'; continue; } if ($ctx==='client') { if (preg_match('/^\s*name\s*:\s*(.+)$/', $line, $mm)) $out['client_name'] = trim($mm[1], " \t\"'"); if (preg_match('/^\s*email\s*:\s*(.+)$/', $line, $mm)) $out['client_email']= trim($mm[1], " \t\"'"); } elseif ($ctx==='property') { if (preg_match('/^\s*address\s*:\s*(.+)$/', $line, $mm)) $out['property_address']= trim($mm[1], " \t\"'"); } } return $out; } /** Tiny contract front-matter extractor used by lookup */ function extract_front_matter_fields(string $file): array { $out = []; $txt = @file_get_contents($file); if (!$txt) return $out; if (!preg_match('/^---\s*\R(.*?)\R---/s', $txt, $m)) return $out; $fm = $m[1]; if (preg_match('/^\s*client\s*:\s*$(.*?)^(?=\S)/ms', $fm."\nX", $block)) { $clientBlock = $block[1]; if (preg_match('/^\s*name\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi', $clientBlock, $mm)) $out['client_name'] = trim($mm[1]); if (preg_match('/^\s*email\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi', $clientBlock, $mm)) $out['client_email'] = trim($mm[1]); if (preg_match('/^\s*address\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi',$clientBlock, $mm)) $out['client_address']= trim($mm[1]); } if (preg_match('/^\s*project\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi', $fm, $mm)) $out['project'] = trim($mm[1]); if (preg_match('/^\s*job\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi', $fm, $mm)) $out['job'] = trim($mm[1]); return $out; } /** Find best-known client + address for a job (checks existing LOA, then contracts) */ function lookup_job_for_loa(string $job): array { $job = preg_replace('/\D+/', '', (string)($_POST['job'] ?? $drg ?? '')); $empty = ['client_name'=>'','client_email'=>'','property_address'=>'','source'=>null]; // Prefer existing LOA $loaFile = loa_path($job); if (is_file($loaFile)) { return extract_loa_fields($loaFile) + ['source'=>'loa']; } // Scan contracts for a matching job or filename foreach (glob(rtrim(CONTRACTS_DIR,'/\\').'/*.md') as $file) { $fm = extract_front_matter_fields($file); $fname_id = preg_replace('/\.md$/i','',basename($file)); if (($fm['job'] ?? '') === $job || $fname_id === $job) { $addr = $fm['client_address'] ?? ''; return [ 'client_name' => $fm['client_name'] ?? '', 'client_email' => $fm['client_email'] ?? '', 'property_address' => $addr, 'source' => 'contract', 'clientid' => $fname_id, ]; } } return $empty; } /* ------------------------ FUNCTIONS ------------------------ */ /** Build a starter Markdown file with YAML front matter. */ if (!function_exists('build_markdown_template')) { function build_markdown_template(string $clientid, ?string $name, ?string $email, ?string $design_style, ?string $phone, ?string $site_address): string { $today = date('Y-m-d'); $name = $name ?? ''; $email = $email ?? ''; $design_style = $design_style ?? ''; $phone = $phone ?? ''; $site_address = $site_address ?? ''; // Generate secure random credentials $adminUser = bin2hex(random_bytes(4)); // 8 hex chars $adminPass = bin2hex(random_bytes(8)); // 16 hex chars $adminSecret = bin2hex(random_bytes(16)); // 32 hex chars $frontMatter = <<$v) { if ($v === '' || $v === null) continue; $lineRe = '/^\s*'.preg_quote($k,'/').'\s*:\s*.*/mi'; $rep = ' '.$k.': '.yaml_q($v); $blk = preg_replace($lineRe, $rep, $blk, 1, $count); if ($count === 0) $blk = rtrim($blk)."\n".$rep."\n"; } return substr_replace($yaml, $blk, $start, $len); } else { $out = rtrim($yaml)."\n".$block.":\n"; foreach ($pairs as $k=>$v) if ($v !== '' && $v !== null) $out .= ' '.$k.': '.yaml_q($v)."\n"; return $out; } } /** Given a full .md file, update its front matter and return updated text */ function update_front_matter_text(string $md, array $kv_top, array $kv_blocks): string { if (!preg_match('/^---\R(.*?)\R---(\R|$)/s', $md, $m, PREG_OFFSET_CAPTURE)) { // add a front matter header if missing $yaml = ""; foreach ($kv_top as $k=>$v) $yaml = yaml_upsert_top($yaml, $k, $v); foreach ($kv_blocks as $b=>$p) $yaml = yaml_upsert_block($yaml, $b, $p); return "---\n".rtrim($yaml)."\n---\n".ltrim($md); } $yaml = $m[1][0]; $start = $m[0][1]; $len = strlen($m[0][0]); foreach ($kv_top as $k=>$v) $yaml = yaml_upsert_top($yaml, $k, $v); foreach ($kv_blocks as $b=>$p) $yaml = yaml_upsert_block($yaml, $b, $p); $newHeader = "---\n".rtrim($yaml)."\n---\n"; return substr_replace($md, $newHeader, $start, $len); } /* -------------------------------------------------------------------------- */ /* API MODE */ /* -------------------------------------------------------------------------- */ $__action = $_GET['action'] ?? $_POST['action'] ?? null; if ($__action === 'loa_create') { try { $job = safe_clientid($_POST['job'] ?? (string)($drg ?? '')); if (!$job) { json_response(['ok'=>false,'error'=>'Missing job #'], 400); exit; } // Form inputs (fall back to blanks) $name = trim($_POST['client_name'] ?? ''); $email = trim($_POST['client_email'] ?? ''); $clientPhone = trim($_POST['client_phone'] ?? ($_POST['client_mobile'] ?? '')); $clientAddress = trim($_POST['client_address'] ?? ($_POST['postal_address'] ?? '')); $addr = trim($_POST['property_address'] ?? ($_POST['site_address'] ?? '')); $propPid = trim($_POST['property_pid'] ?? ($_POST['property_id'] ?? '')); $propTitleRaw = trim($_POST['property_title'] ?? ($_POST['title_id'] ?? '')); // Split things like "140687/4", "140687 - 4", "140687 4" $propVol = ''; $propFolio = ''; if ($propTitleRaw !== '') { if (preg_match('/^\s*([A-Za-z0-9]+)\s*[\/\-\s]\s*([A-Za-z0-9]+)\s*$/', $propTitleRaw, $mm)) { $propVol = $mm[1]; $propFolio = $mm[2]; } else { // If it doesn't split, keep the whole thing in vol so you don't lose info $propVol = $propTitleRaw; } } $dateStart = trim($_POST['start_date'] ?? ''); $dateEnd = trim($_POST['end_date'] ?? ''); $overwrite = (int)($_POST['overwrite'] ?? 0); $dst = loa_path($job); if (!is_dir(LOA_DIR)) @mkdir(LOA_DIR, 0775, true); // What we want in the YAML $top = ['job' => $job]; $blocks = [ 'client' => [ 'name' => $name, 'email' => $email, 'phone' => $clientPhone, 'address' => $clientAddress, ], 'property' => [ 'address' => $addr, 'pid' => $propPid, 'title' => $propTitleRaw, ], 'dates' => [ 'start' => $dateStart, 'end' => $dateEnd, ], ]; // Create new or update existing if (!file_exists($dst)) { // Load template, then inject values into its front matter $tplPath = rtrim(LOA_DIR,'/\\').'/default-authorisation.md'; $tpl = @file_get_contents($tplPath); if ($tpl === false || $tpl === '') $tpl = "# Authorisation\n"; $out = update_front_matter_text($tpl, $top, $blocks); if (@file_put_contents($dst, $out, LOCK_EX) === false) { json_response(['ok'=>false,'error'=>'Write failed'], 500); exit; } json_response(['ok'=>true,'job'=>$job,'path'=>$dst,'public_url'=>loa_public_url($job),'created'=>true]); } else { if ($overwrite) { // Overwrite from template $tplPath = rtrim(LOA_DIR,'/\\').'/default-authorisation.md'; $tpl = @file_get_contents($tplPath); if ($tpl === false || $tpl === '') $tpl = "# Authorisation\n"; $out = update_front_matter_text($tpl, $top, $blocks); } else { // Update front matter only in the existing file $existing = @file_get_contents($dst) ?: ''; $out = update_front_matter_text($existing, $top, $blocks); } if (@file_put_contents($dst, $out, LOCK_EX) === false) { json_response(['ok'=>false,'error'=>'Write failed'], 500); exit; } json_response([ 'ok'=>true,'job'=>$job,'path'=>$dst,'public_url'=>loa_public_url($job), 'created'=>false,'updated_frontmatter'=>!$overwrite ]); } } catch (Throwable $e) { json_response(['ok'=>false,'error'=>$e->getMessage()], 500); } exit; } // ===== end LOA helpers and API ===== // Create the LOA markdown from default-authorisation.md if ($__action === 'loa_create') { try { $job = safe_clientid($_POST['job'] ?? (string)($drg ?? '')); if (!$job) { json_response(['ok'=>false,'error'=>'Missing job #'], 400); exit; } // Prefer explicit POST values; otherwise use current form values already on the page $name = trim($_POST['client_name'] ?? (trim(($firstname ?? '').' '.($lastname ?? '')) ?: ($joint_name ?? ''))); $email = trim($_POST['client_email'] ?? ($client_email ?? '')); $addr = trim($_POST['property_address'] ?? ($site_address ?? '')); $overwrite = (int)($_POST['overwrite'] ?? 0); $dst = loa_path($job); if (!is_dir(LOA_DIR)) @mkdir(LOA_DIR, 0775, true); if (file_exists($dst) && !$overwrite) { json_response(['ok'=>false,'error'=>'File already exists','path'=>$dst], 409); exit; } // Load template (fallback to minimal front-matter if missing) $tplPath = rtrim(LOA_DIR,'/\\').'/default-authorisation.md'; $tpl = @file_get_contents($tplPath); if ($tpl === false || $tpl === '') { $q = fn($v) => '"'.str_replace(['\\','"'], ['\\\\','\\"'], (string)$v).'"'; $tpl = "---\njob: ".$q($job)."\nclient:\n name: ".$q($name)."\n email: ".$q($email)."\nproperty:\n address: ".$q($addr)."\n---\n# Authorisation\n"; } else { // Light YAML substitutions $tpl = preg_replace_callback('/^---\R(.*?)\R---/s', function($m) use($job,$name,$email,$addr){ $yaml = $m[1]; $q = fn($v) => '"'.str_replace(['\\','"'], ['\\\\','\\"'], (string)$v).'"'; // job $yaml = preg_replace('/^\s*job\s*:\s*.*/mi', 'job: '.$q($job), $yaml, 1, $jobCount); if ($jobCount === 0) $yaml = "job: ".$q($job)."\n".$yaml; // ensure blocks exist if (!preg_match('/^\s*client\s*:/mi', $yaml)) $yaml = "client:\n name:\n email:\n".$yaml; if (!preg_match('/^\s*property\s*:/mi', $yaml)) $yaml = "property:\n address:\n".$yaml; // client.name/email $yaml = preg_replace_callback('/(^\s*client\s*:\s*\R(?:.*\R)*?)(?=^\S|\z)/ms', function($b) use($q,$name,$email){ $blk = $b[0]; $blk = preg_replace('/^\s*name\s*:\s*.*/mi', ' name: '.$q($name), $blk, 1, $c1); if ($c1===0) $blk = rtrim($blk)."\n name: ".$q($name)."\n"; $blk = preg_replace('/^\s*email\s*:\s*.*/mi', ' email: '.$q($email), $blk, 1, $c2); if ($c2===0) $blk = rtrim($blk)."\n email: ".$q($email)."\n"; return $blk; }, $yaml, 1); // property.address $yaml = preg_replace_callback('/(^\s*property\s*:\s*\R(?:.*\R)*?)(?=^\S|\z)/ms', function($b) use($q,$addr){ $blk = $b[0]; $blk = preg_replace('/^\s*address\s*:\s*.*/mi', ' address: '.$q($addr), $blk, 1, $p1); if ($p1===0) $blk = rtrim($blk)."\n address: ".$q($addr)."\n"; return $blk; }, $yaml, 1); return "---\n".$yaml."\n---"; }, $tpl, 1) ?? $tpl; } if (@file_put_contents($dst, $tpl, LOCK_EX) === false) { json_response(['ok'=>false,'error'=>'Write failed'], 500); exit; } json_response(['ok'=>true,'job'=>$job,'path'=>$dst,'public_url'=>loa_public_url($job)]); } catch (Throwable $e) { json_response(['ok'=>false,'error'=>$e->getMessage()], 500); } exit; } // Optional: auto-fill data for a job (used by other screens / future) if ($__action === 'loa_lookup') { $job = safe_clientid($_GET['job'] ?? $_POST['job'] ?? ''); $data = $job ? lookup_job_for_loa($job) : ['client_name'=>'','client_email'=>'','property_address'=>'','source'=>null]; $found = (bool)($data['client_name'] || $data['client_email'] || $data['property_address']); json_response(['ok'=>true,'found'=>$found,'data'=>$data]); exit; } /* -------------------------------------------------------------------------- */ /* HELPER FUNCTIONS */ /* -------------------------------------------------------------------------- */ use Google\Client; use Google\Service\Drive; function createFolder(string $access_token, string $folder_name, string $parent_folder_id = ''): ?string { try { $client = new Google\Client(); $client->setAccessToken($access_token); $driveService = new Drive($client); $metadata = new Drive\DriveFile([ 'name' => $folder_name, 'mimeType' => 'application/vnd.google-apps.folder', ]); if ($parent_folder_id) { $metadata->setParents([$parent_folder_id]); } $file = $driveService->files->create($metadata, ['fields' => 'id,name,webViewLink']); return $file->id; } catch (Exception $e) { error_log('createFolder error: ' . $e->getMessage()); return null; } } function createDealHubSpot($newDealData) { global $accessToken; $endpoint = 'https://api.hubapi.com/crm/v3/objects/deals'; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $endpoint, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($newDealData), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $accessToken, // Use OAuth 2.0 token OR 'Authorization: Bearer ' . $apiKey for API key 'Content-Type: application/json' ] ]); $response = curl_exec($curl); curl_close($curl); return $response; } function updateDealHubSpot($dealId, $data) { global $accessToken; $endpoint = 'https://api.hubapi.com/crm/v3/objects/deals/' . $dealId; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $endpoint, CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $accessToken, // Use OAuth 2.0 token OR 'Authorization: Bearer ' . $apiKey for API key 'Content-Type: application/json' ] ]); $response = curl_exec($curl); curl_close($curl); return $response; } function addContactToHubSpot($newContactData) { global $accessToken; $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts'; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $endpoint, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($newContactData), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $accessToken, 'Content-Type: application/json' ] ]); $response = curl_exec($curl); curl_close($curl); return $response; } function searchContact($query) { global $accessToken; $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/search'; $queryJson = json_encode($query); $ch = curl_init($endpoint); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $queryJson); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $accessToken, 'Content-Type: application/json')); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); if (curl_errno($ch)) { echo 'Error making cURL request: ' . curl_error($ch); } curl_close($ch); return $response; } function updateContact($contactId, $data) { global $accessToken; $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/' . $contactId; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $endpoint, CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $accessToken, 'Content-Type: application/json' ] ]); $response = curl_exec($curl); curl_close($curl); return $response; } function format_E164($num) { $phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance(); try { $phoneProto = $phoneUtil->parse($num, "AU"); return [ "phone_number" => $phoneUtil->format($phoneProto, \libphonenumber\PhoneNumberFormat::INTERNATIONAL), "phone_type" => $phoneUtil->getNumberType($phoneProto) ]; } catch (\libphonenumber\NumberParseException $e) { return null; } } if (!empty($drg) and !empty($_POST['add_client_to_crm']) and empty($contactId)) { try { $query = [ "filterGroups" => [ [ "filters" => [ [ "value" => $_POST['firstname'] . "*", "propertyName" => 'firstname', "operator" => "EQ" ], [ "value" => $_POST['lastname'] . "*", "propertyName" => "lastname", "operator" => "EQ" ], [ "value" => $_POST['client_mobile'] . "*", "propertyName" => "phone", "operator" => "EQ" ] ] ] ], ]; $response = json_decode(searchContact($query), true); if ($response['total'] > 0) { echo "

Customer: {$_POST['firstname']} {$_POST['lastname']} already exists in crm, with id: {$response['results'][0]['id']}

"; } else { $newContactData = [ 'properties' => [ 'firstname' => $_POST['firstname'], 'lastname' => $_POST['lastname'], 'description' => 'Added via Online Client Brief Form # ' . $drg, 'company' => $_POST['joint_name'], 'email' => $_POST['client_email'], 'address' => $_POST['postal_address'], 'city' => $_POST['postal_address_town'], 'zip' => $_POST['postal_address_postcode'], 'country' => 'AU', 'state' => $_POST['postal_address_state'], 'hubspot_owner_id' => '585959844', ] ]; if($phone) { if($phone["phone_type"] == \libphonenumber\PhoneNumberType::MOBILE) $newContactData["properties"]["mobilephone"] = $phone["phone_number"]; else $newContactData["properties"]["phone"] = $phone["phone_number"]; } $response = addContactToHubSpot($newContactData); file_put_contents("crmadd.log", $response); $createdContact = json_decode($response, true); if ($createdContact['id'] > 0) { $crm_id = intval($createdContact['id']); $result = mysqli_query($con, "UPDATE details SET crm_id = '{$crm_id}' WHERE drg = '{$drg}'"); if (!$result) { printf("Error: %s\n", mysqli_error($con)); exit(); } else { echo ""; $isHideDismissableAlert = 1; } } } } catch (\Exception $err) { echo '
' . $err->getMessage() . '
'; die(); } } elseif (!empty($drg) and !empty($_POST['edit_client_in_crm']) and !empty($contactId)) { try { $data = [ 'properties' => [ 'firstname' => $_POST['firstname'], 'lastname' => $_POST['lastname'], 'company' => $_POST['joint_name'], 'email' => $_POST['client_email'], 'address' => $_POST['postal_address'], 'city' => $_POST['postal_address_town'], 'zip' => $_POST['postal_address_postcode'], 'country' => 'AU', 'state' => $_POST['postal_address_state'], 'hubspot_owner_id' => '585959844', ] ]; if($phone) { if($phone["phone_type"] == \libphonenumber\PhoneNumberType::MOBILE) $data["properties"]["mobilephone"] = $phone["phone_number"]; else $data["properties"]["phone"] = $phone["phone_number"]; } $query = [ "filterGroups" => [ [ "filters" => [ [ "value" => $_POST['firstname'] . "*", "propertyName" => 'firstname', "operator" => "EQ" ], [ "value" => $_POST['lastname'] . "*", "propertyName" => "lastname", "operator" => "EQ" ], [ "value" => $_POST['client_mobile'] . "*", "propertyName" => "phone", "operator" => "EQ" ] ] ] ], ]; $response = json_decode(searchContact($query), true); if ($response['total'] > 0) { $response = updateContact($contactId, $data); $result = mysqli_query($con, "UPDATE details SET crm_id = '{$response['id']}' WHERE drg = '{$drg}'"); file_put_contents("crmupdate.log", $response); $response = json_decode($response, true); if ($response['id'] > 0) { echo ""; $isHideDismissableAlert = 1; } } else { $response = addContactToHubSpot($newContactData); file_put_contents("crmadd.log", $response); $createdContact = json_decode($response, true); if ($createdContact['id'] > 0) { $crm_id = intval($createdContact['id']); echo ""; $isHideDismissableAlert = 1; } } } catch (\Exception $err) { echo '
Crm Id: ' . $contactId . ', response: ' . $err->getMessage() . '
'; die(); } } // Create Deal from Enquiry Form if (!empty($quid) and !empty($_POST['add_deal_to_hubspot']) and empty($dealId)) { try { $newDealData = [ 'associations' => [ [ 'types' => [ [ 'associationCategory' => 'HUBSPOT_DEFINED', 'associationTypeId' => 3, ] ], 'to' => [ 'id' => $_POST['crm_id'] ], ] ], 'properties' => [ 'dealname' => $_POST['quid'] . ' - ' . $_POST['client'], 'dealtype' => 'newbusiness', // New or Existing Business - do we do a sql lookup and see if there is some won jobs for this customer ?? 'hubspot_owner_id' => $_POST['hubspot_owner_id'], 'createdate' => $_POST['enquiry_date'], //assign deal to contact with hubspot contact id //'associatedCompanyIds' => $_POST['company_id'], 'pipeline' => '64401721', 'dealstage' => '126963334', 'width' => str_replace('m', '', $_POST['width']), 'length' => str_replace('m', '', $_POST['length']), 'height' => str_replace('m', '', $_POST['height']), 'quote_type' => $_POST['quote_type'], 'type' => $_POST['product'], 'roof_type' => $_POST['roof_style'], 'sides' => $_POST['side_walls'], 'ends' => $_POST['end_walls'], 'internal' => $_POST['internal_walls'], 'qty_bays' => $_POST['bay_qty'], //'bay_width' => $_POST['bay_width'], //'uneven_bays' => $_POST['bay_uneven'], 'quote' => $_POST['quid'], ] ]; $response = createDealHubSpot($newDealData); file_put_contents("crmdeal.log", $response); $createdDeal = json_decode($response, true); if ($createdDeal['id'] > 0) { $dealId = intval($createdDeal['id']); $result = mysqli_query($con, "UPDATE details SET dealId = '{$dealId}' WHERE drg = '{$drg}'"); echo ""; $isHideDismissableAlert = 1; } } catch (\Exception $err) { echo '
' . $err->getMessage() . '
'; die(); } } elseif (!empty($drg) and !empty($_POST['update_deal_in_hubspot']) and !empty($dealId)) { try { $updateDealData = [ 'properties' => [ 'dealname' => $_POST['drg'] . ' - ' . $_POST['client'], 'hubspot_owner_id' => $_POST['hubspot_owner_id'], 'createdate' => $_POST['enquiry_date'], //assign deal to contact with hubspot contact id //'associatedCompanyIds' => $_POST['company_id'], 'quote_type' => $_POST['quote_type'], 'type' => $_POST['product'], ], 'associations' => [ 'types' => [ 'association_category' => 'HUBSPOT_DEFINED', 'association_type_id' => 3 ], 'to' => [ 'id' => $_POST['crm_id'] ] ] ]; $response = updateDealHubSpot($dealId, $updateDealData); file_put_contents("crmdeal.log", $response); $updatedDeal = json_decode($response, true); if ($updatedDeal['id'] > 0) { $dealId = intval($updatedDeal['id']); echo ""; $isHideDismissableAlert = 1; } } catch (\Exception $err) { echo '
' . $err->getMessage() . '
'; die(); } } if (!empty($_GET['drg'])) { $contact_button = ''; if ($crm_id > 5) { $contact_button = ''; } else { $contact_button = ''; } } ?> <?php echo $drg; ?> - Client Brief

Job:

Client Brief Form


Client Details


Proposed Site Details


Design Brief


Brief Checklist

Have the following documents being provided?

>
>
>
>
>
>

Design Outputs

>
>
>
>
>
>

Presentations

>
>
>

Create Documents


Investment Details


Services Used




© 2023 - Modulos Design