Send template message in WeChat mini program

According to the WeChat Development document, a field form_id should be presented when requesting a template message to be sent to the user. But the problem is that one template message for one corresponding form can’t meet all the needs. So we need to keep collecting available form_ids for future template message sending.

And according to this document, form with filed report-submit can provide a  valid form_id. Thus we can create a subclass for button to collecting available form_ids.

We name this class sbutton, codes on the mini-program side read:

<!--sbutton.wxml-->
<form bindsubmit="btnClick" report-submit>
  <button formType="submit"><slot></slot></button>
</form>
{
  "component": true,
  "usingComponents": {}
}
/* sbutton.wxss */
// sbutton.js
Component({
  /**
   * List of component properties
   */
  properties: {

  },

  /**
   * Initial data of the component
   */
  data: {
    requested: false,
  },

  /**
   * List of component methods
   */
  methods: {
    btnClick: function (e) {
      let formId = e.detail.formId
      if ('the formId is a mock one' !== formId
          && false ===this.data.requested) {
        // TODO: send formId to the backend
        // Set this.data.requested to be true when success
      }
      this.triggerEvent('Tap', e, {})
    }
  },


})

After then, we can replace button with sbutton safely. For example,

<button bindtap="onConfirm">Confirm</button>

could be replaced with

<sbutton bindtap="onConfirm">Confirm</sbutton>

In the corresponding json file of the component, add usingComponents record pointing to the sbutton.

{
  "usingComponents": {
    "sbutton": "path/to/your/sbutton"
  }
}

On the server side, we need to keep and clean out-dated form_ids. The example for Golang reads

package wechat

import (
	"errors"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"model/db"
	"strconv"
	"time"
)

/* WeChat Mini Program Template Message FormId */
type WxTempMsgFormId struct {
	WxOpenId  string
	FormId    string
	Timestamp int64
}

var conn *gorm.DB

func init() {
	var err error
	conn, err = gorm.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", "db_username", "db_password", "db_host", "db_port", "db_name"))
	if err != nil {
		panic(err.Error())
	}

	conn.AutoMigrate(&WxTempMsgFormId{})

	go clean_worker()
}

func FormIdSave(wxOpenId string, formId string) {
	conn.Save(WxTempMsgFormId{
		WxOpenId:  wxOpenId,
		FormId:    formId,
		Timestamp: time.Now().Unix(),
	})
}

func FormIdConsume(wxOpenId string) (string, error) {
	record := WxTempMsgFormId{WxOpenId: wxOpenId}
	conn.Where(record).First(&record)
	if "" != record.FormId {
		db.Conn.Delete(&record)
		return record.FormId, nil
	} else {
		return "", errors.New("No more available form_id for user " + wxOpenId)
	}
}

func clean_worker() {
	for {
		threshold := time.Now().Unix() - 3600*24*6 // 6 days ago

		db.Conn.Where("timestamp < " + strconv.FormatInt(threshold, 10)).Delete(&WxTempMsgFormId{})
		time.Sleep(time.Hour * 1)
	}
}

The last step is to send template message with valid form_id from our pool.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.