K3cloud SDK

Ruby Gem for Kingdee K3Cloud OpenApi. Uses cryptographic signature technology to avoid plaintext transmission of keys and supports automatic login.

Table of Contents

Installation

Install the gem and add it to a Rails application's Gemfile:

$ bundle add k3cloud-sdk

If bundler is not being used to manage dependencies, install the gem by executing:

$ gem install k3cloud-sdk

Configuration

Single Account

Configure it in config/initializers/k3cloud.rb:

K3cloud.configure do |config|
  config.acct_id    = ENV["K3CLOUD_ACCT_ID"]
  config.user_name  = ENV["K3CLOUD_USERNAME"]
  config.app_id     = ENV["K3CLOUD_APP_ID"]
  config.app_secret = ENV["K3CLOUD_APP_SECRET"]
  config.server_url = ENV["K3CLOUD_SERVER_URL"] # blank for public cloud
end

Then call the K3Cloud API directly:

data = {
  FormId: "PRD_MO",
  FieldKeys: "FMaterialId.FNumber, FNoStockInQty",
  FilterString: "FStatus not in (6, 7)"
}
K3cloud.execute_bill_query(data)

Multi Account

Create multiple K3cloud::Configuration instances and build clients for each:

config1 = K3cloud::Configuration.new do |c|
  c.acct_id    = ENV["K3CLOUD1_ACCT_ID"]
  c.user_name  = ENV["K3CLOUD1_USERNAME"]
  c.app_id     = ENV["K3CLOUD1_APP_ID"]
  c.app_secret = ENV["K3CLOUD1_APP_SECRET"]
  c.server_url = ENV["K3CLOUD1_SERVER_URL"]
end

config2 = K3cloud::Configuration.new do |c|
  c.acct_id    = ENV["K3CLOUD2_ACCT_ID"]
  c.user_name  = ENV["K3CLOUD2_USERNAME"]
  c.app_id     = ENV["K3CLOUD2_APP_ID"]
  c.app_secret = ENV["K3CLOUD2_APP_SECRET"]
  c.server_url = ENV["K3CLOUD2_SERVER_URL"]
end

client1 = K3cloud.new_api(config1)
client2 = K3cloud.new_api(config2)

client1.execute_bill_query(data)
client2.execute_bill_query(data)

Optional Settings

Option Default Description
verify_ssl true HTTPS certificate verification. Only affects https URLs (http URLs skip SSL automatically). Set false for private cloud self-signed certificates.
connect_timeout 30 Connection timeout in seconds.
request_timeout 60 Request read timeout in seconds.
retry_max 3 Max retries on timeout / 5xx. 0 disables retry.
retry_interval 1 First retry interval in seconds, then exponential backoff.
retry_backoff 2 Backoff multiplier between retries.
log_format :text Logger output format: :text or :json.
K3cloud.configure do |config|
  # ... required fields above ...
  config.verify_ssl       = true
  config.connect_timeout  = 30
  config.request_timeout  = 60
  config.retry_max        = 3
  config.retry_interval   = 1
  config.log_format       = :json
end

Error Handling

All request failures raise K3cloud::ResponseError. A missing or invalid configuration raises K3cloud::ConfigurationError on the first request. Wrap calls accordingly:

begin
  K3cloud.save("PRD_MO", data)
rescue K3cloud::ConfigurationError => e
  # missing config: app_id / app_secret / acct_id / user_name
  logger.error("Config error: #{e.message}")
rescue K3cloud::ResponseError => e
  # network or Kingdee business error
  logger.error("Request failed: #{e.message}")
end

In Scheduled Jobs (Sidekiq / cron / rake)

The SDK raises K3cloud::ResponseError after retries are exhausted. Always rescue explicitly in scheduled jobs to prevent the exception from bubbling up and failing the container/process:

class SyncK3cloudJob
  def perform
    rows = K3cloud.execute_bill_query_all({ FormId: "PRD_MO" }, limit: 1000)
    # ... process rows ...
  rescue K3cloud::ConfigurationError => e
    logger.error("[k3cloud] config error: #{e.message}")
  rescue K3cloud::ResponseError => e
    logger.error("[k3cloud] request failed: #{e.message}")
    # Re-raise so the scheduler (e.g. Sidekiq) can retry the job
    raise e
  end
end

Tip: In scheduled jobs, set a small retry_max (e.g. 0 or 1) and let the job scheduler decide the next attempt, instead of sleeping inside the SDK and occupying the worker thread. For example: K3cloud.configure { |c| c.retry_max = 1 }.

Available API Methods

All methods are available on both:

  • K3cloud.<method> — uses the default account (delegates to K3cloud.default_api).
  • K3cloud.new_api(config).<method> — uses a specific account configuration.

Bill Operations

Method Signature Description
draft draft(form_id, data) Temporarily save a bill (暂存).
save save(form_id, data) Save a bill (保存).
batch_save batch_save(form_id, data) Batch save bills (批量保存).
submit submit(form_id, data) Submit a bill (提交).
audit audit(form_id, data) Audit a bill (审核).
un_audit un_audit(form_id, data) Un-audit a bill (反审核).
view view(form_id, data) View a bill detail (查看).
delete delete(form_id, data) Delete a bill (删除).
cancel_assign cancel_assign(form_id, data) Cancel assignment (撤销).
push push(form_id, data) Push down a bill (下推).
execute_operation execute_operation(form_id, op_number, data) Status transition: close/reopen/void/unvoid etc. (状态转换).
allocate allocate(form_id, data) Allocate a bill (分配).
cancel_allocate cancel_allocate(form_id, data) Cancel allocation (取消分配).
disassembly disassembly(form_id, data) Disassembly operation (拆单).
flex_save flex_save(form_id, data) Flex save (弹性域保存).
send_msg send_msg(form_id, data) Send message (发送消息).

Query Operations

Method Signature Description
execute_bill_query execute_bill_query(data) Query bills with parameters { FormId:, FieldKeys:, FilterString: } (单据查询). Returns a 2D array; returns [] on error.
execute_bill_query_all execute_bill_query_all(data, limit: 1000) Paginated query that fetches all bill rows by auto-injecting StartRow and Limit until a page returns fewer than limit rows (分页批量查询). Returns the merged 2D array.

Example:

# Single-page query (you handle pagination manually)
rows = K3cloud.execute_bill_query(
  FormId: "PRD_MO",
  FieldKeys: "FMaterialId.FNumber, FNoStockInQty",
  FilterString: "FStatus not in (6, 7)",
  StartRow: 0,
  Limit: 100
)

# Paginated query (SDK handles pagination for you)
all_rows = K3cloud.execute_bill_query_all(
  { FormId: "PRD_MO", FieldKeys: "FMaterialId.FNumber", FilterString: "" },
  limit: 1000
)

Group Operations

Method Signature Description
group_save group_save(form_id, data) Save a group (分组保存).
query_group_info query_group_info(data) Query group info (分组信息查询).
group_delete group_delete(data) Delete a group (分组删除).

Attachment Operations

Method Signature Description
attachment_upload attachment_upload(data) Upload an attachment (附件上传).
attachment_download attachment_download(data) Download an attachment (附件下载).

Metadata & Report Operations

Method Signature Description
query_business_info query_business_info(data) Query business metadata (元数据查询).
get_sys_report_data get_sys_report_data(form_id, data) Query system report data (查询报表数据).

Workflow & Organization Operations

Method Signature Description
workflow_audit workflow_audit(data) Workflow audit (工作流审核).
switch_org switch_org(data) Switch organization (切换组织).

Logger

By default, logs are written to $stderr in plain text. You can switch to JSON-per-line format (useful for log aggregation) or inject your own logger.

# JSON format
K3cloud.configure { |c| c.log_format = :json }
K3cloud.reset_logger! # rebuild the default logger after changing log_format

# Inject a custom logger (e.g. Rails.logger)
K3cloud.logger = Rails.logger

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/zevinto/k3cloud-sdk. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the K3cloud-sdk project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.