Can't auto create new data in another site

Hi, i am currently need to make a custom where i create “work order” and then submit it, it will automatically create an additional salary but in different site. The problem is that i already developer the code but got this error

Failed to create Additional Salary for employee HR-EMP-00007: 417 Client Error: EXPECTATION FAILED for url: http://192.168.1.161:8002/api/resource/Additional%20Salary

is anyone can help me/ thanks a lot

Hi @AmateurDeveloper

To create record from outsite you need API keys also.

But i already input the api key, and got that error

Hi @AmateurDeveloper:

It seems related to the request header … (Status 417) … check your header info. It’s working from Postman/Bruno/… ?

below i give my code maybe you could help. Bcs i still have no idea about the error

def create_delete_additional_salary_on_hr_site(members, list_employee, doctype, name, list_additional_salary, project):
create_add_sal = set(list_employee) - set(list_additional_salary)
delete_add_sal = set(list_additional_salary) - set(list_employee)

for member in create_add_sal:
	create_additional_salary_on_hr_site(member, doctype, name, project)

for member in delete_add_sal:
	delete_additional_salary_on_hr_site(member, doctype, name)

def create_additional_salary_on_hr_site(employee, doctype, docname, project):
data = {
“employee”: employee,
“salary_component”: frappe.db.get_value(“Payroll Settings”, “Payroll Settings”, “salary_component_bonus”),
“payroll_date”: nowdate(),
“type”: “Earning”,
“remarks”: project,
“amount”: 0,
“ref_doctype”: doctype,
“ref_docname”: docname
}
headers = {
“Authorization”: f"token {hr_api_key}:{hr_api_token}“,
“Expect”: “”
}
try:
response = requests.post(f”{hr_site_url}/api/resource/Additional Salary", json=data, headers=headers)
response.raise_for_status()
except requests.exceptions.RequestException as e:
frappe.log_error(f"Failed to create Additional Salary for employee {employee}: {e}“, “SPK Additional Salary Creation Error”)
frappe.throw(f"Failed to create Additional Salary for employee {employee}. Please check the logs.”)

def delete_additional_salary_on_hr_site(employee, doctype, docname):
try:
additional_salary_name = frappe.db.get_value(
“Additional Salary”,
{“ref_doctype”: doctype, “ref_docname”: docname, “docstatus”: [“!=”, 2], “employee”: employee},
“name”
)
if additional_salary_name:
response = requests.delete(f"{hr_site_url}/api/resource/Additional Salary/{additional_salary_name}“, headers={
“Authorization”: f"token {hr_api_key}:{hr_api_token}”
})
response.raise_for_status()
except requests.exceptions.RequestException as e:
frappe.log_error(f"Failed to delete Additional Salary for employee {employee}: {e}“, “SPK Additional Salary Deletion Error”)
frappe.throw(f"Failed to delete Additional Salary for employee {employee}. Please check the logs.”)

Hi @AmateurDeveloper:

Is your code copy/pasted as is? Or you changed some info for privacy? :sweat_smile:

Anyway, I would recommend use Frappeclient.

Just import it and use regular methods get_doc, get_list …

Hope this helps.

wait i’ll give you the whole code, i just modify some info for privacy hehe
this is my code, maybe you could help me mpdify, thanks

import frappe
from frappe.model.document import Document
import datetime
import requests
from requests.exceptions import RequestException
from frappe.utils import nowdate
from frappe.model.workflow import get_workflow_name
from frappe.workflow.doctype.workflow_action.workflow_action import get_doc_workflow_state

class SuratPerintahKerja(Document):
def on_update(self):
if not get_workflow_name(self.get(“doctype”)):
return

	check_additional_salary(self)

def before_cancel(self):
	self.check_role_and_set_workflow()
	check_additional_salary(self,cancel=True)

def on_trash(self):
	check_additional_salary(self)

def check_role_and_set_workflow(self):
	self.workflow_state = "Cancelled"
	workflow_name = get_workflow_name(self.get("doctype"))
	allow_edit_role = frappe.get_value("Workflow Document State", filters={'doc_status': 2, 'parent': workflow_name}, fieldname='allow_edit')
	roles = frappe.get_roles(frappe.session.user)
	if allow_edit_role not in roles:
		frappe.throw("Current User doesn't have Role {} to Cancel this Document".format(allow_edit_role))

def check_additional_salary(self, cancel=False):
list_additional_salary = frappe.db.get_list(“Additional Salary”, {“ref_doctype”:self.doctype, “ref_docname”:self.name, “docstatus”:[“!=”,2]}, “employee”)
list_additional_salary = [d[‘employee’] for d in list_additional_salary]

list_employee = []
if cancel == False:
	for m in self.team_members:
		list_employee.append(m.employee_member)
	
	for m in self.production_members:
		list_employee.append(m.employee)

create_delete_additional_salary_on_hr_site(self.team_members, list_employee, self.doctype, self.name, list_additional_salary, self.project_name)

def create_delete_additional_salary_on_hr_site(members, list_employee, doctype, name, list_additional_salary, project):
create_add_sal = set(list_employee) - set(list_additional_salary)
delete_add_sal = set(list_additional_salary) - set(list_employee)

for member in create_add_sal:
	create_additional_salary_on_hr_site(member, doctype, name, project)

for member in delete_add_sal:
	delete_additional_salary_on_hr_site(member, doctype, name)

def create_additional_salary_on_hr_site(employee, doctype, docname, project):
try:
hr_site_url = “http://192.168.1.111:8002

	for member in doc.team_members:
		data = {
			"employee": employee,
			"salary_component": frappe.db.get_value("Payroll Settings", "Payroll Settings", "salary_component_bonus"),
			"payroll_date": nowdate(),
			"type": "Earning",
			"remarks": project,
			"amount": 0,
			"ref_doctype": doctype,
			"ref_docname": docname
		}

		frappe.log_error(data, "Additional Salary Data")

		headers = {
			"Authorization": "token 283f56976bf429a:46gf391f353d891",
			"Content-Type": "application/json"
		}

		response = requests.post(f"{hr_site_url}/api/resource/Additional%20Salary", json=data, headers=headers)

		if response.status_code == 200:
			frappe.msgprint(f"Additional Salary has created successfully in HR Internal site.")
		else:
			frappe.throw(f"Failed to create Additional Salary on HR Internal site. Status: {response.status_code} - {response.text}")
	
except Exception as e:
	frappe.log_error(f"Error creating Additional Salary {str(e)}", "SPK Additional Salary Creation")

def delete_additional_salary_on_hr_site(employee, doctype, docname):
try:
additional_salary_name = frappe.db.get_value(
“Additional Salary”,
{“ref_doctype”: doctype, “ref_docname”: docname, “docstatus”: [“!=”, 2], “employee”: employee},
“name”
)
if additional_salary_name:
response = requests.delete(f"{hr_site_url}/api/resource/Additional Salary/{additional_salary_name}“, headers={
“Authorization”: f"token {hr_api_key}:{hr_api_token}”
})
response.raise_for_status()
except requests.exceptions.RequestException as e:
frappe.log_error(f"Failed to delete Additional Salary for employee {employee}: {e}“, “SPK Additional Salary Deletion Error”)
frappe.throw(f"Failed to delete Additional Salary for employee {employee}. Please check the logs.”)

Hi @AmateurDeveloper:

Check your token, it should base64 encoded.
BTW, explore FrappeClient … it will help you a lot :wink:

i’ve tried, but i got error 403 like this:
Failed to create Additional Salary for employee H-EM-00007: 403 Client Error: FORBIDDEN for url: http://192.168.1.111:8002/api/resource/Additional%20Salary

any suggestion?
and i’ve tried frappeclient to, but it keep showing error like “no module named frappeclient”