def handle(self, *args, **options): tenant = Tenant.objects.get(pk=options['tenant_id']) if tenant: credentials = get_credentials('pandadoc', tenant) if credentials: logger.info('Syncing documents for tenant %s' % tenant.id) # Get all current documents. tenant_documents = Document.objects.filter(tenant=tenant) url = 'https://api.pandadoc.com/public/v1/documents' # Get all documents from PandaDoc. response = send_get_request(url, credentials) if response.status_code == 200: documents = response.json().get('results') for document in documents: document_id = document.get('id') # Document doesn't exist (so something probably went wrong while creating the quote). if not tenant_documents.filter(document_id=document_id): details_url = url + '/%s/details' % document_id response = send_get_request(details_url, credentials) if response.status_code == 200: deal_id = response.json().get('metadata').get('deal') if deal_id: deal = Deal.objects.get(pk=deal_id) document = Document.objects.create( contact=deal.contact, deal=deal, document_id=document_id, tenant=tenant, ) self.imported_documents_count += 1 else: message = '[PandaDoc] Something went wrong while syncing document %s: ' % document_id message = message + response.text logger.warning(message) else: message = '[PandaDoc] Something went while syncing documents: ' + response.json() logger.warning(message) else: message = '[PandaDoc] Tenant %s doesn\'t have PandaDoc credentials' % options['tenant_id'] logger.warning(message) logger.info('%s documents have been imported' % self.imported_documents_count) else: logger.error('Please enter a valid tenant')
def get(self, request, contact_id, format=None): """ List all Moneybird estimates. """ credentials = get_credentials('moneybird') url = 'https://moneybird.com/api/v2/%s/estimates' % credentials.integration_context.get('administration_id') response = send_get_request(url, credentials) data = response.json() return Response({'estimates': data})
def get(self, request, contact_id, format=None): documents = Document.objects.filter(contact=self.kwargs['contact_id']) temp_documents = [] credentials = get_credentials(IntegrationDetails.PANDADOC) for document in documents: url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document.document_id response = send_get_request(url, credentials) data = response.json() if data.get('id'): temp_documents.append(data) else: # No details could be retreived, so it's probably been deleted in PandaDoc. document.delete() return Response({'documents': temp_documents})
def get(self, request, contact_id, format=None): """ List all PandaDoc documents. """ documents = Document.objects.filter(contact=self.kwargs['contact_id']) temp_documents = [] credentials = get_credentials('pandadoc') for document in documents: url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document.document_id response = send_get_request(url, credentials) data = response.json() if data.get('id'): temp_documents.append(data) else: # No details could be retreived, so it's probably been deleted in PandaDoc. document.delete() return Response({'documents': temp_documents})
def get(self, request, deal_id, format=None): """ List all PandaDoc documents. """ documents = Document.objects.filter(deal_id=deal_id) temp_documents = [] credentials = get_credentials('pandadoc') for document in documents: url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document.document_id response = send_get_request(url, credentials) data = response.json() if data.get('id'): temp_documents.append(data) else: # No details could be retreived, so it's probably been deleted in PandaDoc. document.delete() return Response({'documents': temp_documents})
def import_moneybird_contacts(tenant_id): importing = True page = 1 tenant = Tenant.objects.get(pk=tenant_id) # Can't retreive tenant from request here, so get the tenant. credentials = get_credentials('moneybird', tenant) administration_id = credentials.integration_context.get( 'administration_id') # New tenants have this account status, but older tenants might not. account_status, status_created = AccountStatus.objects.get_or_create( name='Customer', tenant=tenant) base_url = 'https://moneybird.com/api/v2/%s/contacts?page=%s&per_page=100' while importing: url = base_url % (administration_id, page) response = send_get_request(url, credentials) data = response.json() if data: for contact_data in data: # For every field we want to fill we do the following: # 1. Setup a dict with the information. # 2. Retrieve all objects with that info. # 3. If no object exists, create a new one (and add to set for related objects). try: with transaction.atomic(): contact = None first_name = contact_data.get('firstname') last_name = contact_data.get('lastname', '') if first_name: contact_dict = { 'first_name': first_name, 'last_name': last_name, 'tenant': tenant, 'is_deleted': False } # Since we have the possibility to resync we want to update # contacts that might already exist. contact = Contact.objects.filter( **contact_dict).last() if not contact: contact = Contact.objects.create( **contact_dict) company = contact_data.get('company_name') if company: account_dict = { 'name': company, 'status': account_status, 'tenant': tenant, 'is_deleted': False } account = Account.objects.filter( **account_dict).last() if not account: account = Account.objects.create( **account_dict) if contact: # Contacts and accounts are linked through functions. Function.objects.get_or_create(account=account, contact=contact) if contact: # Save all contact info to the contact if there is one. contact_object = contact else: # Otherwise use the account. contact_object = account invoices_email = contact_data.get( 'send_invoices_to_email') estimates_email = contact_data.get( 'send_estimates_to_email') phone = contact_data.get('phone') address = contact_data.get('address1') alternate_address = contact_data.get('address2') if invoices_email: invoices_email_dict = { 'email_address': invoices_email, 'tenant': tenant, } invoices_email_address = contact_object.email_addresses.filter( **invoices_email_dict) if not invoices_email_address.last(): invoices_email_address = EmailAddress.objects.create( **invoices_email_dict) contact_object.email_addresses.add( invoices_email_address) if estimates_email and not invoices_email == estimates_email: # No point in adding two of the same email addresses. estimates_email_dict = { 'email_address': estimates_email, 'tenant': tenant, } estimates_email_address = contact_object.email_addresses.filter( **estimates_email_dict) if not estimates_email_address.last(): estimates_email_address = EmailAddress.objects.create( **estimates_email_dict) contact_object.email_addresses.add( estimates_email_address) if phone: phone_number_dict = { 'number': phone, 'tenant': tenant, } phone_number = contact_object.phone_numbers.filter( **phone_number_dict).last() if not phone_number: phone_number = PhoneNumber.objects.create( **phone_number_dict) contact_object.phone_numbers.add(phone_number) if address: postal_code = contact_data.get('zipcode') city = contact_data.get('city') country = contact_data.get('country') address_dict = { 'address': address, 'postal_code': postal_code, 'city': city, 'country': country, 'tenant': tenant, } address = Address.objects.filter( **address_dict).last() if not address: address = Address.objects.create( **address_dict) contact_object.addresses.add(address) if alternate_address: address_dict = ({ 'address': alternate_address, 'country': country, 'tenant': tenant, }) alternate_address = Address.objects.filter( **address_dict).last() if not alternate_address: alternate_address = Address.objects.create( **address_dict) contact_object.addresses.add( alternate_address) contact_object.save() except Exception as e: logger.error(e) # Increment the page so we can check for more contacts. page += 1 else: importing = False
def get(self, request, *args, **kwargs): template = EmailTemplate.objects.get(pk=kwargs.get('template_id')) lookup = {'user': self.request.user} errors = {} if 'account_id' in self.request.GET: try: account = Account.objects.get(pk=self.request.GET.get('account_id')) except Account.DoesNotExist: pass else: lookup.update({'account': account}) if 'contact_id' in self.request.GET: try: contact = Contact.objects.get(pk=self.request.GET.get('contact_id')) except Contact.DoesNotExist: pass else: lookup.update({'contact': contact}) functions = contact.functions.all() if len(functions) == 1: try: account = Account.objects.get(pk=functions[0].account_id) except Account.DoesNotExist: pass else: lookup.update({'account': account}) if 'document_id' in self.request.GET: credentials = get_credentials('pandadoc') if credentials: error_message = None document_id = self.request.GET.get('document_id') recipient = self.request.GET.get('recipient_email') details_url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document_id response = send_get_request(details_url, credentials) if response.status_code == 200: # Only documents with the 'draft' status can be set to sent. if response.json().get('status') == 'document.draft': # Set the status of the document to 'sent' so we can create a view session. send_url = 'https://api.pandadoc.com/public/v1/documents/%s/send' % document_id send_params = {'silent': True} response = send_post_request(send_url, credentials, send_params) if response.status_code != 200: error_message = 'Something went wrong while setting up the PandaDoc sign URL.' metadata = response.json().get('metadata') if metadata and metadata.get('account'): account_id = metadata.get('account') try: account = Account.objects.get(pk=account_id) except Account.DoesNotExist: pass else: lookup.update({'account': account}) # Document has been 'sent' so create the session. session_url = 'https://api.pandadoc.com/public/v1/documents/%s/session' % document_id year = 60 * 60 * 24 * 365 session_params = {'recipient': recipient, 'lifetime': year} response = send_post_request(session_url, credentials, session_params) if response.status_code == 201: sign_url = 'https://app.pandadoc.com/s/%s' % response.json().get('id') lookup.update({'document': {'sign_url': sign_url}}) else: error_message = ('The PandaDoc sign URL could not be created \ because the recipient isn\'t correct') else: error_message = 'The document doesn\'t seem to be valid.' if error_message: errors.update({ 'document': error_message }) if 'emailaccount_id' in self.request.GET: try: emailaccount = EmailAccount.objects.get(pk=self.request.GET.get('emailaccount_id')) except EmailAccount.DoesNotExist: pass else: lookup.get('user').current_email_address = emailaccount.email_address # Setup regex to find custom variables search_regex = '\[\[ custom\.(.*?) \]\]' # Find all occurrences. search_result = re.findall(search_regex, template.body_html) if search_result: for custom_variable in search_result: public = None try: # Try to split to see if it's a public variable variable, public = custom_variable.split('.') except ValueError: # Not a public variable, so .split raises an error variable = custom_variable if public: template_variable = TemplateVariable.objects.filter( name__iexact=variable, is_public=True ) else: template_variable = TemplateVariable.objects.filter( name__iexact=variable, owner=get_current_user() ) if template_variable: # find = '\[\[ custom.' + custom_variable + '(\s)?\]\]' find = re.compile('\[\[ custom\.' + custom_variable + ' \]\]') replace = template_variable.first().text template.body_html = re.sub(find, replace, template.body_html, 1) # Ugly hack to make parsing of new template brackets style work parsed_template = Template(template.body_html.replace('[[', '{{').replace(']]', '}}')).render(Context(lookup)) parsed_subject = Template(template.subject.replace('[[', '{{').replace(']]', '}}')).render(Context(lookup)) # Make sure HTML entities are displayed correctly html_parser = HTMLParser.HTMLParser() parsed_subject = html_parser.unescape(parsed_subject) attachments = [] for attachment in template.attachments.all(): # Get attachment name name = get_attachment_filename_from_url(attachment.attachment.name) attachments.append({ 'id': attachment.id, 'name': name, }) return HttpResponse(anyjson.serialize({ 'template': parsed_template, 'template_subject': parsed_subject, 'attachments': attachments, 'errors': errors, }), content_type='application/json')
def send_moneybird_contact(self, validated_data, instance, credentials, original_data=None): administration_id = credentials.integration_context.get( 'administration_id') contact_url = 'https://moneybird.com/api/v2/%s/contacts' if original_data: full_name = original_data.get('full_name') else: full_name = instance.full_name search_url = (contact_url + '?query=%s') % (administration_id, full_name) response = send_get_request(search_url, credentials) data = response.json() patch = False params = {} if data: data = data[0] moneybird_id = data.get('id') post_url = (contact_url + '/%s') % (administration_id, moneybird_id) params = { 'id': moneybird_id, } # Existing Moneybird contact found so we want to PATCH. patch = True else: post_url = contact_url % administration_id if 'first_name' in validated_data: params.update({'firstname': validated_data.get('first_name')}) if 'last_name' in validated_data: params.update({'lastname': validated_data.get('last_name')}) accounts = instance.accounts.all() if 'accounts' in validated_data and len(accounts) == 1: params.update({'company_name': accounts[0].name}) if 'phone_numbers' in validated_data: phone_numbers = [] for validated_number in validated_data.get('phone_numbers'): for phone_number in instance.phone_numbers.all(): if validated_number.get('number') == phone_number.number: phone_numbers.append(phone_number) break if phone_numbers: params.update({'phone': phone_numbers[0].number}) if 'addresses' in validated_data: addresses = [] for validated_address in validated_data.get('addresses'): for address in instance.addresses.all(): if validated_address.get('address') == address.address: addresses.append(address) break if addresses: address = addresses[0] params.update({ 'address1': address.get('address'), 'zipcode': address.get('postal_code'), 'city': address.get('city'), 'country': address.get('country'), }) if 'email_addresses' in validated_data: validated_email_addresses = validated_data.get('email_addresses') original_email_address = original_data.get( 'original_email_address') if len(validated_email_addresses) == 1 and original_email_address: if data: invoices_email = data.get('send_invoices_to_email') estimates_email = data.get('send_estimates_to_email') validated_email_address = validated_email_addresses[0].get( 'email_address') if invoices_email == estimates_email and invoices_email == original_email_address: params.update({ 'send_invoices_to_email': validated_email_address, 'send_estimates_to_email': validated_email_address, }) elif invoices_email == original_email_address: params.update({ 'send_invoices_to_email': validated_email_address, }) elif estimates_email == original_email_address: params.update({ 'send_estimates_to_email': validated_email_address, }) params = {'contact': params, 'administration_id': administration_id} response = send_post_request(post_url, credentials, params, patch, True)
def send_moneybird_contact(self, validated_data, instance, credentials, original_data=None): administration_id = credentials.integration_context.get('administration_id') contact_url = 'https://moneybird.com/api/v2/%s/contacts' if original_data: full_name = original_data.get('full_name') else: full_name = instance.full_name search_url = (contact_url + '?query=%s') % (administration_id, full_name) response = send_get_request(search_url, credentials) data = response.json() patch = False params = {} if data: data = data[0] moneybird_id = data.get('id') post_url = (contact_url + '/%s') % (administration_id, moneybird_id) params = { 'id': moneybird_id, } # Existing Moneybird contact found so we want to PATCH. patch = True else: post_url = contact_url % administration_id if 'first_name' in validated_data: params.update({'firstname': validated_data.get('first_name')}) if 'last_name' in validated_data: params.update({'lastname': validated_data.get('last_name')}) accounts = instance.accounts.all() if 'accounts' in validated_data and len(accounts) == 1: params.update({'company_name': accounts[0].name}) if 'phone_numbers' in validated_data: phone_numbers = [] for validated_number in validated_data.get('phone_numbers'): for phone_number in instance.phone_numbers.all(): if validated_number.get('number') == phone_number.number: phone_numbers.append(phone_number) break if phone_numbers: params.update({'phone': phone_numbers[0].number}) if 'addresses' in validated_data: addresses = [] for validated_address in validated_data.get('addresses'): for address in instance.addresses.all(): if validated_address.get('address') == address.address: addresses.append(address) break if addresses: address = addresses[0] params.update({ 'address1': address.address, 'zipcode': address.postal_code, 'city': address.city, 'country': address.country, }) if 'email_addresses' in validated_data: original_email_address = None validated_email_addresses = validated_data.get('email_addresses') if original_data: original_email_address = original_data.get('original_email_address') if len(validated_email_addresses) == 1: validated_email_address = validated_email_addresses[0].get('email_address') if data and original_email_address: invoices_email = data.get('send_invoices_to_email') estimates_email = data.get('send_estimates_to_email') if invoices_email == estimates_email and invoices_email == original_email_address: params.update({ 'send_invoices_to_email': validated_email_address, 'send_estimates_to_email': validated_email_address, }) elif invoices_email == original_email_address: params.update({ 'send_invoices_to_email': validated_email_address, }) elif estimates_email == original_email_address: params.update({ 'send_estimates_to_email': validated_email_address, }) else: params.update({ 'send_invoices_to_email': validated_email_address, 'send_estimates_to_email': validated_email_address, }) params = { 'contact': params, 'administration_id': administration_id } response = send_post_request(post_url, credentials, params, patch, True)
def get(self, request, *args, **kwargs): template = EmailTemplate.objects.get(pk=kwargs.get('template_id')) lookup = {'user': self.request.user} errors = {} if 'account_id' in self.request.GET: try: account = Account.objects.get( pk=self.request.GET.get('account_id')) except Account.DoesNotExist: pass else: lookup.update({'account': account}) if 'contact_id' in self.request.GET: try: contact = Contact.objects.get( pk=self.request.GET.get('contact_id')) except Contact.DoesNotExist: pass else: lookup.update({'contact': contact}) functions = contact.functions.all() if len(functions) == 1: try: account = Account.objects.get( pk=functions[0].account_id) except Account.DoesNotExist: pass else: lookup.update({'account': account}) if 'document_id' in self.request.GET: credentials = get_credentials('pandadoc') if credentials: error_message = None document_id = self.request.GET.get('document_id') recipient = self.request.GET.get('recipient_email') details_url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document_id response = send_get_request(details_url, credentials) if response.status_code == 200: # Only documents with the 'draft' status can be set to sent. if response.json().get('status') == 'document.draft': # Set the status of the document to 'sent' so we can create a view session. send_url = 'https://api.pandadoc.com/public/v1/documents/%s/send' % document_id send_params = {'silent': True} response = send_post_request(send_url, credentials, send_params) if response.status_code != 200: error_message = 'Something went wrong while setting up the PandaDoc sign URL.' metadata = response.json().get('metadata') if metadata and metadata.get('account'): account_id = metadata.get('account') try: account = Account.objects.get(pk=account_id) except Account.DoesNotExist: pass else: lookup.update({'account': account}) # Document has been 'sent' so create the session. session_url = 'https://api.pandadoc.com/public/v1/documents/%s/session' % document_id year = 60 * 60 * 24 * 365 session_params = {'recipient': recipient, 'lifetime': year} response = send_post_request(session_url, credentials, session_params) if response.status_code == 201: sign_url = 'https://app.pandadoc.com/s/%s' % response.json( ).get('id') lookup.update({'document': {'sign_url': sign_url}}) else: error_message = ( 'The PandaDoc sign URL could not be created \ because the recipient isn\'t correct' ) else: error_message = 'The document doesn\'t seem to be valid.' if error_message: errors.update({'document': error_message}) if 'emailaccount_id' in self.request.GET: try: emailaccount = EmailAccount.objects.get( pk=self.request.GET.get('emailaccount_id')) except EmailAccount.DoesNotExist: pass else: lookup.get( 'user').current_email_address = emailaccount.email_address # Setup regex to find custom variables search_regex = '\[\[ custom\.(.*?) \]\]' # Find all occurrences. search_result = re.findall(search_regex, template.body_html) if search_result: for custom_variable in search_result: public = None try: # Try to split to see if it's a public variable variable, public = custom_variable.split('.') except ValueError: # Not a public variable, so .split raises an error variable = custom_variable if public: template_variable = TemplateVariable.objects.filter( name__iexact=variable, is_public=True) else: template_variable = TemplateVariable.objects.filter( name__iexact=variable, owner=get_current_user()) if template_variable: # find = '\[\[ custom.' + custom_variable + '(\s)?\]\]' find = re.compile('\[\[ custom\.' + custom_variable + ' \]\]') replace = template_variable.first().text template.body_html = re.sub(find, replace, template.body_html, 1) # Ugly hack to make parsing of new template brackets style work parsed_template = Template( template.body_html.replace('[[', '{{').replace(']]', '}}')).render( Context(lookup)) parsed_subject = Template( template.subject.replace('[[', '{{').replace(']]', '}}')).render( Context(lookup)) # Make sure HTML entities are displayed correctly html_parser = HTMLParser.HTMLParser() parsed_subject = html_parser.unescape(parsed_subject) attachments = [] for attachment in template.attachments.all(): # Get attachment name name = get_attachment_filename_from_url(attachment.attachment.name) attachments.append({ 'id': attachment.id, 'name': name, }) return HttpResponse(anyjson.serialize({ 'template': parsed_template, 'template_subject': parsed_subject, 'attachments': attachments, 'errors': errors, }), content_type='application/json')
def import_moneybird_contacts(tenant_id): importing = True page = 1 tenant = Tenant.objects.get(pk=tenant_id) # Can't retreive tenant from request here, so get the tenant. credentials = get_credentials('moneybird', tenant) administration_id = credentials.integration_context.get('administration_id') # New tenants have this account status, but older tenants might not. account_status, status_created = AccountStatus.objects.get_or_create(name='Customer', tenant=tenant) base_url = 'https://moneybird.com/api/v2/%s/contacts?page=%s&per_page=100' while importing: url = base_url % (administration_id, page) response = send_get_request(url, credentials) data = response.json() if data: for contact_data in data: # For every field we want to fill we do the following: # 1. Setup a dict with the information. # 2. Retrieve all objects with that info. # 3. If no object exists, create a new one (and add to set for related objects). try: with transaction.atomic(): contact = None first_name = contact_data.get('firstname') last_name = contact_data.get('lastname', '') if first_name: contact_dict = { 'first_name': first_name, 'last_name': last_name, 'tenant': tenant, 'is_deleted': False } # Since we have the possibility to resync we want to update # contacts that might already exist. contact = Contact.objects.filter(**contact_dict).last() if not contact: contact = Contact.objects.create(**contact_dict) company = contact_data.get('company_name') if company: account_dict = { 'name': company, 'status': account_status, 'tenant': tenant, 'is_deleted': False } account = Account.objects.filter(**account_dict).last() if not account: account = Account.objects.create(**account_dict) if contact: # Contacts and accounts are linked through functions. Function.objects.get_or_create(account=account, contact=contact) if contact: # Save all contact info to the contact if there is one. contact_object = contact else: # Otherwise use the account. contact_object = account invoices_email = contact_data.get('send_invoices_to_email') estimates_email = contact_data.get('send_estimates_to_email') phone = contact_data.get('phone') address = contact_data.get('address1') alternate_address = contact_data.get('address2') if invoices_email: invoices_email_dict = { 'email_address': invoices_email, 'tenant': tenant, } invoices_email_address = contact_object.email_addresses.filter(**invoices_email_dict) if not invoices_email_address.last(): invoices_email_address = EmailAddress.objects.create(**invoices_email_dict) contact_object.email_addresses.add(invoices_email_address) if estimates_email and not invoices_email == estimates_email: # No point in adding two of the same email addresses. estimates_email_dict = { 'email_address': estimates_email, 'tenant': tenant, } estimates_email_address = contact_object.email_addresses.filter(**estimates_email_dict) if not estimates_email_address.last(): estimates_email_address = EmailAddress.objects.create(**estimates_email_dict) contact_object.email_addresses.add(estimates_email_address) if phone: phone_number_dict = { 'number': phone, 'tenant': tenant, } phone_number = contact_object.phone_numbers.filter(**phone_number_dict).last() if not phone_number: phone_number = PhoneNumber.objects.create(**phone_number_dict) contact_object.phone_numbers.add(phone_number) if address: postal_code = contact_data.get('zipcode') city = contact_data.get('city') country = contact_data.get('country') address_dict = { 'address': address, 'postal_code': postal_code, 'city': city, 'country': country, 'tenant': tenant, } address = Address.objects.filter(**address_dict).last() if not address: address = Address.objects.create(**address_dict) contact_object.addresses.add(address) if alternate_address: address_dict = ({ 'address': alternate_address, 'country': country, 'tenant': tenant, }) alternate_address = Address.objects.filter(**address_dict).last() if not alternate_address: alternate_address = Address.objects.create(**address_dict) contact_object.addresses.add(alternate_address) contact_object.save() except Exception as e: logger.error(e) # Increment the page so we can check for more contacts. page += 1 else: importing = False